博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
适配多种数据结构和ui的万能适配器
阅读量:7074 次
发布时间:2019-06-28

本文共 9945 字,大约阅读时间需要 33 分钟。

hot3.png

首页作为app的访问最多的页面,注定是拥有丰富的ui元素,要驾驭这么多的ui元素并不影响性能的话,listview是个非常适合的选择,问题是不同的元素需要的数据结构体也不一样,item的布局文件也不一样。该如何处理呢

这是万能适配器应运而生了,主要思路是通过一个map来记录list中元素的种类,之后就是让对应的item都继承于同一个接口,统一调用adapter的getView方法进行模版化的渲染动作,具体的渲染交给各种item的方法来进行,在初始化的时候,主需要传递数据集和对应的ui布局文件就可以了。

核心代码

MultiCollectionAdapter
public abstract class MultiCollectionAdapter extends BaseAdapter {    final SparseArray
mMapOfTypeViewList; final SparseIntArray mMapOfLayoutIdType; public MultiCollectionAdapter() { mMapOfTypeViewList = new SparseArray<>(10); mMapOfLayoutIdType = new SparseIntArray(10); } public MultiCollectionAdapter(SparseArray
mapOfTypeViewList,SparseIntArray mapOfLayoutIdType) { this.mMapOfTypeViewList = mapOfTypeViewList; this.mMapOfLayoutIdType = mapOfLayoutIdType; } public int getLayoutId(int position) { if (null != mMapOfLayoutIdType && mMapOfLayoutIdType.size() != 0) { int itemViewType = getItemViewType(position); return mMapOfLayoutIdType.get(itemViewType); } else { throw new IllegalStateException("please override "+getClass().getName()+".getLayoutId or build by "+getClass().getName()+"(SparseArray
,SparseArray
)"); } } public void putLayoutId(int key, int layoutId) { mMapOfLayoutIdType.put(key, layoutId); } public void updateData(int key,List list) { mMapOfTypeViewList.put(key, list); notifyDataSetChanged(); } public void removeData(int key) { mMapOfTypeViewList.delete(key); notifyDataSetChanged(); } public void appendData(int key, List list) { mMapOfTypeViewList.append(key, list); notifyDataSetChanged(); } @Override public int getCount() { int size = 0; for(int i = 0; i< mMapOfTypeViewList.size(); i++ ) { int key = mMapOfTypeViewList.keyAt(i); List list = mMapOfTypeViewList.get(key); size += getSizeOfListValue(list); } return size; } @Override public int getItemViewType(int position) { int prt = 0; int type = 0; for(int i = 0; i < mMapOfTypeViewList.size(); i++) { int key = mMapOfTypeViewList.keyAt(i); List list = mMapOfTypeViewList.get(key) ; prt += getSizeOfListValue(list); if (prt > position) { type = key; break; } } return type; } @Override public Object getItem(int position) { int size = 0; List list = null; int i = 0; for(; i < mMapOfTypeViewList.size(); i++) { int key = mMapOfTypeViewList.keyAt(i); list = mMapOfTypeViewList.get(key); size += getSizeOfListValue(list); if (size -1 >= position) { break; } } int p = getSizeOfListValue(list) - size + position; if (null!=list && 0 != list.size()) { return list.get(p); } return null; } protected int getSizeOfListValue(List list) { if(null!=list) return list.size(); else return 1; } @Override public long getItemId(int position) { return position; } @Override public View getView(final int position, View convertView, ViewGroup parent) { final CommonViewHolder viewHolder = getViewHolder(position, convertView, parent); convert(viewHolder, getItem(position)); View view = viewHolder.getConvertView(); return view; } public abstract void convert(CommonViewHolder helper, Object item); public boolean useCustomListSelector() { return false; } public SparseArray
getData() { return mMapOfTypeViewList; } private CommonViewHolder getViewHolder(int position, View convertView, ViewGroup parent) { return CommonViewHolder.get(convertView, parent, getLayoutId(position), position); } private MultiLayoutAdapter.OnItemClickListener mItemClickListener; public void setOnItemClickListener(MultiLayoutAdapter.OnItemClickListener listener) { mItemClickListener = listener; } public interface OnItemClickListener{ void onItemClick(int position, Object data, View itemView); }}

 万能适配器负责管理两个map,一个mMapOfLayoutIdType是元素类型列表,记录list中的所有类型

另一个是mMapOfTypeViewList,记录各个类型对应的数据集,相当一个二维数组,第一维是layoutId,第二层是元素对应的数据集list

要做到适配不同的item,必须重写getItem方法(从list获取item数据)和getItemViewType方法

因为只有position这个参数可用,所以需要通过判断当前position落于哪一段,才能拿到正确的类型

值得注意的是getSizeOfListValue方法默认返回一个1,因为之后的判断会进行减

 

适配器最重要的方法莫过于getView

这里只是一个模版代码

final CommonViewHolder viewHolder = getViewHolder(position, convertView, parent);        convert(viewHolder, getItem(position));        View view = viewHolder.getConvertView();

convert方法是一个抽象方法,子类必须实现这个方法,相当于baseAdapter的getView方法,不过这里封装成传递的参数是更为实用的CommenViewHolder和对应的数据结构体(item的)

CommenViewHolder可以理解为封装好的ui的管理器,本身不是view,但只能通过

View convertView = helper.getConvertView();

获取converView

public class CommonViewHolder {	private final SparseArray
mViews; private final int mLayoutId; private int mPosition; private final View mConvertView; public int getLayoutId() { return mLayoutId; } private CommonViewHolder(ViewGroup parent, int layoutId, int position) { this.mPosition = position; this.mViews = new SparseArray
(); this.mLayoutId = layoutId; // TODO mConvertView = LayoutInflater.from(parent.getContext()).inflate(layoutId, null); mConvertView.setTag(this); } public static CommonViewHolder get(View convertView, ViewGroup parent, int layoutId, int position) { CommonViewHolder holder = null; if (convertView == null || ((CommonViewHolder) convertView.getTag()).getLayoutId() != layoutId) { holder = new CommonViewHolder(parent, layoutId, position); } else { holder = (CommonViewHolder) convertView.getTag(); holder.mPosition = position; } return holder; } public View getConvertView() { return mConvertView; } @SuppressWarnings("unchecked") public
T getView(int viewId) { View view = mViews.get(viewId); if (view == null) { view = mConvertView.findViewById(viewId); mViews.put(viewId, view); } return (T) view; } public CommonViewHolder setText(int viewId, String text) { TextView view = getView(viewId); view.setText(text); return this; } public CommonViewHolder setImageResource(int viewId, int drawableId) { ImageView view = getView(viewId); if (view != null) { view.setImageResource(drawableId); } return this; } public CommonViewHolder setImageBitmap(int viewId, Bitmap bm) { ImageView view = getView(viewId); view.setImageBitmap(bm); return this; } public int getPosition() { return mPosition; }}

 

通用viewholder,需要传入layoutId初始化,,初始化的时候,每个mConverView都会被打标签,然后在get方法,通过标签获取view,如果为空,则再new一个,new的同时也把标签打好了,由此做到复用converView,这种设计把复用的代码搬到CommenViewHolder中进行,有针对性。毕竟adapter主要处理的是数据,ui方面的处理交给CommenViewHolder处理就可以了。

private class MyListViewAdapter extends MultiCollectionAdapter {        static final int TYPE_HEAD_SELECTOR = 0;        static final int TYPE_SELECTOR = 1;        static final int TYPE_LAST_ITEM = 6;        RecommendListViewAdapter(SparseArray
mapOfTypeViewList, SparseIntArray mapOfLayoutIdType) { super(mapOfTypeViewList, mapOfLayoutIdType); } @Override public void convert(CommonViewHolder helper, Object item) { View convertView = helper.getConvertView(); if (convertView instanceof HolderViewListItem) { ((HolderViewListItem) convertView).setup(item); } } }

适配器的导出类很简单,只需要重写convert方法就可以了,需要注意的是,convert方法里面也是模版代码

具体的实现交给对应的item类处理即可,调用item的setUp方法

关于我一值提到的item,就是真正意义上的ui实现类,继承于Viewgroup,并实现接口HolderViewListItem

public interface HolderViewListItem
{ void setup(T obj); void onItemClick(View.OnClickListener listener);}

为什么item都要实现这个接口呢,因为convert方法里面用到的是模版代码,获取的都是HolderViewListItem类型,并且使用了setup方法,这种方式,非常灵活,item可以根据需要实现多个接口,但各个接口之间并不影响,执行

 ((HolderViewListItem) convertView).setup(item);方法的时候,编辑器会通过向下转型自动找到对应的实现类,并准确得调用setup方法,这也是接口的基本用法。对外提供统一接口,运行时解析成具体的方法,统一封装代码,降低耦合性,各司其职。

现在来看看item的实现类

public class MyListItem extends RelativeLayout implements HolderViewListItem
{ private TextView mText; public MyListItem (Context context) { super(context); } public MyListItem (Context context, AttributeSet attrs) { super(context, attrs); } public MyListItem (Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(); } public static MyListItem newInstance(Context context) { return (MyListItem ) LayoutInflater.from(context).inflate(R.layout.item_main_my_list_item, null); } private void initView() { mText = (TextView) findViewById(R.id.main_item_text); } @Override public void setup(final MyInfo data) { initView(); mText.setText(data.modelName); } @Override public void onItemClick(OnClickListener listener) { setOnClickListener(listener); }}

item的布局文件里面,根目录也是这个类的引用,在这里就不列出来了

以上只是零部件,接下来看看如何组装

实例化万能适配器

mAdapter = new ListViewAdapter(generateDataCollection(), generateLayoutIdCollection());
private SparseArray
generateDataCollection() { SparseArray
map = new SparseArray<>(10); map.put(MyListViewAdapter.TYPE_HEAD_SELECTOR, null); map.append(MyListViewAdapter.TYPE_SELECTOR, selectorData); return map; } private SparseIntArray generateLayoutIdCollection() { SparseIntArray map = new SparseIntArray(10); map.put(MyListViewAdapter.TYPE_HEAD_SELECTOR, R.layout.widget_main_selector_head); map.append(MyListViewAdapter.TYPE_SELECTOR, R.layout.item_main_selector); return map; }

刷新的用法和平常的用法一样

 

 

 

转载于:https://my.oschina.net/carbenson/blog/907560

你可能感兴趣的文章
Wireshark网络抓包(二)——过滤器
查看>>
Ubuntu系统主题及插件工具等官方地址
查看>>
Linux 特殊目录
查看>>
AnguarJs-01-HelloWorld
查看>>
实现前端MD5加密与记住用户名密码功能
查看>>
command for cut
查看>>
Fortinet安全能力融入华为CloudEPN 联合防御网络威胁
查看>>
使用yum安装MariaDB
查看>>
RHEL7.2配置安装MariaDB数据库
查看>>
百度云管家 v 5.5.0 破解安装版
查看>>
语音识别技术受追捧,无法独立工作的“速记神器”何时才能成为新亮点?
查看>>
对Context的重新思考
查看>>
Win8 Metro(C#)数字图像处理--2.43图像马赛克效果算法
查看>>
SQLite第二课 源码下载编译
查看>>
ibatis动态生成列时的列名无效
查看>>
通用汽车新增130辆测试无人车,配激光雷达
查看>>
python之通过“反射”实现不同的url指向不同函数进行处理(反射应用一)
查看>>
10.6 监控io性能;10.7 free;10.8 ps;10.9 查看网络状态;10.10 抓包
查看>>
delegate的用法
查看>>
Ubuntu <2TB sdb preseed示例
查看>>