Adapter的封装
来源:互联网 发布:东华软件股份公司官网 编辑:程序博客网 时间:2024/06/06 21:38
简述
先前在一微信讨论组里讨论起adapter和viewholder的抽取,有的说他们项目里用的是抽得他妈都不认识…他妈都不认识那还怎么用? 也看了github上几个开源出来的抽取方法,有的抽取过度,有的不便使用,还要自己记id什么的,感觉都不是很满意,于是回头看看自己项目里封装的,感觉还是比较合理的,兼顾了可读性和重用性,封装也适度,于是把它放出来,与大家交流交流.
抽取封装BaseAdapter的基本原理(以listview为例)
convertview:
listview本身提供的复用机制,缓存的是item的rootview,避免了每次getview都去将整个xml解析成一个view对象.
内部是若干个View数组,数组个数等于getItemTypeCount(),每次getview方法的参数里传入的convertview对象就是根据getItemType(pisition)在指定的数组中取缓存的view.
viewholder
缓存了itemview内部需要用到的各个子view对象,避免了每次getview时都从rootview对象中findviewById,减少了xml解析的时间.
viewholder的复用是通过与converview绑定,借用convertview的复用机制来达到复用的效果.绑定与取出是通过view.settag(obj)和view.gettag()来实现的.
封装技巧
viewholder
不仅封装了各子view对象,也同时封装rootview对象,便于设定整个item的点击事件,长按事件,这样就避开了对listview设置onItemClickListener时可能发生的无焦点等坑爹事件.
提供设置布局的xml的方法,让子类实现,用@LayoutRes注解限定返回值.
使用Butterkinfe结合其对应的android studio插件来快速生成view对象的代码.
将数据和事件设置到各view上封装成统一的方法,让adapter里直接调用holder的方法,而无多余代码. 数据ben采用泛型,让子类实现时直接指定.
代码:
public abstract class SuperLvHolder<T> { public View rootView; public SuperLvHolder(Activity context){ rootView = View.inflate(context,setLayoutRes(),null); ButterKnife.bind(this,rootView); } protected abstract @LayoutRes int setLayoutRes(); /** * 一般情况下,实现这个方法就足够了 * @param context * @param bean */ public abstract void assingDatasAndEvents(Activity context, T bean); /** * 如果有需要,才实现这个方法 * @param context activity实例,用于一些点击事件 * @param bean 该条目的数据 * @param position 该条目所在的位置 * @param isLast 是否为最后一条,有些情况下需要用到 * @param isListViewFling listview是不是在惯性滑动,备用.一般图片加载框架会提供全局暂停和恢复的方法,无需此参数 * @param datas 整个listview对应的数据 * @param superAdapter adapter对象引用,可用于触发notifydatesetChanged()方法刷新整个listview,比如更改的单选按钮 */ public void assingDatasAndEvents(Activity context, T bean, int position ,boolean isLast, boolean isListViewFling,List datas, SuperLvAdapter superAdapter){ assingDatasAndEvents(context,bean); }}
adapter
继承BaseAdapter,四个抽象方法都用重写,getview里方法使用上面封装好的viewholder,只需要提供一个抽象方法generateNewHolder(int itemtype).而且,即使是多种type的item,也无需更改getview里的逻辑.
adapter 对外提供添加数据,刷新数据,删除数据等功能,这些功能抽取成接口并让adapter实现。
adapter不指定数据类型,因为多种类型时,可能会有多种数据类型。
/*** 单一的item* Created by Administrator on 2016/4/15 0015.*/public abstract class SuperLvAdapter extends BaseAdapter implements Refreshable { List datas; Activity context; boolean isListViewFling; public boolean isListViewFling() { return isListViewFling; } public void setListViewFling(boolean listViewFling) { isListViewFling = listViewFling; } public SuperLvAdapter(@NonNull List datas, Activity context){ if (datas == null){ throw new RuntimeException("datas cannot be null"); } this.datas = datas; this.context = context; } @Override public int getCount() { if (datas == null ) return 0; return datas.size(); } @Override public Object getItem(int position) { if (datas == null) return null; return datas.get(position); } @Override public long getItemId(int position) { if (datas == null){ return 0; } return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { SuperLvHolder holder = null; if (convertView == null){ holder = generateNewHolder(context,getItemViewType(position));//考虑多种类型的item convertView = holder.rootView; convertView.setTag(holder); }else { holder = (SuperLvHolder) convertView.getTag(); } holder.assingDatasAndEvents(context,datas.get(position),position,position == getCount() -1,isListViewFling,datas,this); return convertView; } protected abstract SuperLvHolder generateNewHolder(Activity context, int itemViewType);//子类需要实现的唯一方法 @Override public void refresh(List newData){ if (newData == null){ datas.clear(); notifyDataSetChanged(); return; } if (datas == null){ datas = newData; notifyDataSetChanged(); }else { datas.clear(); datas.addAll(newData); notifyDataSetChanged(); } } @Override public void addAll(List newData){ if (newData == null){ return; } if (datas == null){ datas = newData; notifyDataSetChanged(); }else { datas.addAll(newData); notifyDataSetChanged(); } } @Override public void clear(){ if (datas != null){ datas.clear(); notifyDataSetChanged(); } } @Override public void delete(int position){ if (datas != null && position < getCount()){ datas.remove(position); notifyDataSetChanged(); } } public List getListData(){ return datas; } @Override public void add(Object object) { if (object ==null) return; try { datas.add(object); notifyDataSetChanged(); }catch (Exception e){ } }}
RecycleView的adapter封装形式类似
有一点不同是ViewHolder必须继承RecyView.ViewHolder,构造函数被限定只能传一个itemview对象进来,所以layout文件id不能封装到holder内部,只能从外部指定并inflate成view后传递进来.
public abstract class SuperRcvHolder<T> extends RecyclerView.ViewHolder { public View rootView;//用于外部对itemview的引用操作 public SuperRcvHolder(View itemView) { super(itemView); rootView = itemView; ButterKnife.bind(this,rootView); }....}
使用
使用技巧:
listview,recycleview的数据与界面达到完全的一一对应,如果服务器返回的数据不对应,那么重新组合,如果有一个item无需数据,那么在datas里插入null或无意义的数据,holder多一种类型来处理即可.
SuperLvAdapter:
单一类型item时,使用匿名实现类即可,多种类型时,重写getItemViewTypeCount和getItemViewType(position) 即可,无需更改getview内部的逻辑.
SuperLvHolder:
写子类的时候在子类内部指定layout文件,一般情况下,实现assingDatasAndEvents(Activity context, String bean)就可以,如果要用到int position ,boolean isLast,就实现更多参数的同名方法,此时,上面那个简化的方法空实现即可.
如果该holder在多个地方使用,那么可以作为单独的类,达到复用的目的.
SuperRcvAdapter和SuperRcvHolder
adapter一般情况下都使用匿名子类.多个item时分别指定类型和对应的hoder即可.
holder一般也使用匿名子类.如果在其他页面需要复用,那么可以写成单独的子类.其layout文件需要在构造函数前传入,已封装好方法.
示例代码
AbstractListview 的 SuperLvAdapter:
adapter:
ListView listView = new ListView(this); ArrayList<String> datas = new ArrayList<>(); SuperLvAdapter adapter = new SuperLvAdapter(datas, this) { @Override protected SuperLvHolder generateNewHolder(Activity context,int viewType) { return new CustomHolder(context); } }; listView.setAdapter(adapter); adapter.add("hhhh");
viewholder的实现:
class CustomHolder extends SuperLvHolder<String> { @Bind(R.id.tv_text) TextView mTvText; public CustomHolder(Activity context) { super(context); } @Override protected int setLayoutRes() { return R.layout.holder_demo_list; } @Override public void assingDatasAndEvents(Activity context, String bean) { mTvText.setText(bean); }}
RecycleView 的 SuperRcvAdapter:
SuperRcvAdapter,多种类型下的使用
mAdapter = new SuperRcvAdapter(datas, mActivity) { public static final int TYPE_0 = 0; public static final int TYPE_1 = 1; @Override protected SuperRcvHolder generateCoustomViewHolder(int viewType) { switch (viewType) { case TYPE_0: return new CustomHolder(inflate(R.layout.holder_demo_list)); case TYPE_1: return new CustomHolder2(inflate(R.layout.holder_demo_list_2)); default: return new SuperRcvHolder<String>(inflate(R.layout.holder_demo_list_2)) {//匿名子类 private TextView tv_text; @Override public void assignDatasAndEvents(Activity context, String data) { super.assignDatasAndEvents(context, data); tv_text.setText(data); } }; } } @Override public int getItemViewType(int position) { if (position % 2 == 0) {//偶数位 return TYPE_0; } else {//奇数位 return TYPE_1; } } }; mRecyclerView.setAdapter(mAdapter);
holder的实现:
class CustomHolder extends SuperRcvHolder<String> { @Bind(R.id.tv_text) TextView mTvText; public CustomHolder(View itemView) { super(itemView); } @Override public void assignDatasAndEvents(Activity context, String data) { mTvText.setText(data); } //备用 @Override public void assignDatasAndEvents(Activity context, String data, int position, boolean isLast, boolean isListViewFling, List datas, SuperRcvAdapter superRecyAdapter) { super.assignDatasAndEvents(context, data, position, isLast, isListViewFling, datas, superRecyAdapter); }}
代码地址
SuperAdapter : https://github.com/glassLake/SuperAdapter
- RecycleView Adapter的封装
- adapter的封装
- Adapter的简单封装
- Adapter的封装
- RecyclerView.Adapter的封装
- Recycleview的adapter封装
- 封装的Adapter的优缺点
- ReCycleView的 Adapter的封装
- android 简单的adapter封装
- 封装的viewholder和adapter
- Recyclerview Adapter 的简单封装
- RecyclerView.Adapter 的简单封装
- Android---封装ListView的Adapter
- 简单封装RecyclerView的Adapter
- 商城之Adapter的封装
- Android 封装RecyclerView的Adapter
- RecyclerView.Adapter的基本封装
- 关于RecyclerView的Adapter封装
- vs2015配置opencv
- # 读写锁类ReadWriteLock #
- Docker容器及Spring Boot微服务应用
- AlertDialog对话框-自定义View
- html手机端调用手机相册和摄像头
- Adapter的封装
- Java高并发框架Quasar
- # Linux常用命令 #
- lintcode,带最小值操作的栈
- mac常用shell命令
- python 数据处理中的 LabelEncoder 和 OneHotEncoder
- vim缩进
- writeup-FLAG 实验吧
- Mysql数据库一个字段中存有另一个表中的多ID