Android中recycleview的adapter封装
2017-04-28 本文已影响586人
昵称真难选
原文出自王艳涛的专栏转载请注明出处!
概述
android开发中经常用到ListView、RecycleView等列表控件,为了增强这类控件的显示和灵活应用,需要自己继承和重写android提供的adapter类。但是android提供的adapter都比较抽象,重写时会产生大量重复代码,所以进行封装后再使用是一个很必要的步骤。
既然是封装就要达到下面两个要求:
- 代码:尽量减少重复代码;
- 功能:能够方便的获取Item布局中控件,并进行操作。
未封装的adapter
首先分析下未封装时的adapter使用代码
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private LayoutInflater layoutInflater;
private Context context;
List<MyData> data;//有自定义的类,改进:引入泛型
public MyAdapter(Context context) {
this.context = context;
layoutInflater = LayoutInflater.from(context);
}
public void setData(List<MyData> data) {//有自定义的类,改进:引入泛型
this.data = data;
notifyDataSetChanged();
}
public List<MyData> getData() {//有自定义的类,改进:引入泛型
return data;
}
@Override
public int getItemCount() {
return data == null ? 0 : data.size();
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = layoutInflater.inflate(R.layout.item_news_list1, parent, false);
//有自定义的Holder实例,改进:从单独封装的Holder基类中获取
return new MyHolder(view);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
//有自定义的操作,声明一个抽象方法,让子类继承去实现
((MyHolder) holder).tvTitle.setText(data.getTitle());
}
//自定义的Holder类,改进:单独封装为一个Holder基类
public class MyHolder extends RecyclerView.ViewHolder {
TextView tvTitle, tvSource, tvPubDate;
public MyHolder(View itemView) {
super(itemView);
tvTitle = (TextView) itemView.findViewById(R.id.tvTitle);
}
}
}
从上面代码可以看出,影响adapter复用主要有三个方面的因素:
- 每次使用adapter时,都需要传进一个集合数据,类型是自定义的,如List中的MyData等,所以进行封装成基类adapter时,应该消除基类对集合数据类型敏感性,解决方案为:引入泛型。
- Myholder作为adapter的内部类,不同的adapter一般需要不同的holder,所以内部类的形式影响adapter的复用,解决方案为:将holder抽出,单独封装为一个holder基类。
- onBindViewHoler()中的操作是自定义操作,实现逻辑不应该放在封装的adapter中,应该下放到子类adapter中,解决方案为:定义一个抽象方法,让子类继承实现。
封装
封装的adapter(主要是增强代码的复用)
public abstract class BaseAdp<T> extends RecyclerView.Adapter<BaseHolder> {
Context context;
List<T> data;//引入泛型
int layoutId;
public BaseAdp(Context context, List<T> data, int layoutId) {
this.context = context;
this.data = data;
this.layoutId = layoutId;
}
public void setData(List<T> data) {
this.data = data;
}
public List<T> getData() {
return this.data;
}
@Override
public int getItemCount() {
return data == null ? 0 : data.size();
}
@Override
public BaseHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//从holder基类中获取holder
return BaseHolder.getHolder(context, parent, layoutId);
}
@Override
public void onBindViewHolder(BaseHolder holder, int position) {
//调用由子类实现的抽象方法,将操作下放到子类中
onBind(holder, data.get(position), position);
}
//抽象方法,让子类继承实现
public abstract void onBind(BaseHolder holder, T t, int position);
}
封装的holder基类(主要是增强对Item的控制)
向外层暴露getView()、setOnclickListener()两个方法,使外层得到控制Item内部控件的能力。
public class BaseHolder extends RecyclerView.ViewHolder {
View itemView;
SparseArray<View> views;//存放Item中的控件
public BaseHolder(View itemView){
super(itemView);
this.itemView = itemView;
views = new SparseArray<View>();
}
//供adapter调用,返回holder
public static <T extends BaseHolder> T getHolder(Context cxt, ViewGroup parent, int layoutId){
return (T) new BaseHolder(LayoutInflater.from(cxt).inflate(layoutId, parent, false));
}
//根据Item中的控件Id获取控件
public <T extends View> T getView(int viewId){
View childreView = views.get(viewId);
if (childreView == null){
childreView = itemView.findViewById(viewId);
views.put(viewId, childreView);
}
return (T) childreView;
}
//根据Item中的控件Id向控件添加事件监听
public BaseHolder setOnClickListener(int viewId, View.OnClickListener listener){
View view = getView(viewId);
view.setOnClickListener(listener);
return this;
}
}
封装后的adapter使用
使用时让自己的adapter继承封装好的BaseAdapter,只需要实现构造函数和onBind()两个函数即可,大大降低了重复代码,同时借助封装的BaseHolder获得了控制Item内部控件和向其指定事件监听的能力。
public class MyAdapter extends BaseAdapter<Contact>{
public MyAdapter(Context context, List<Contact> data, int layoutId) {
super(context, data, layoutId);
}
@Override
public void onBind(BaseHolder holder, final Contact contact, int position) {
//根据控件Id获取Item内部的控件
TextView tvName = holder.getView(R.id.tvName);
tvName.setText(contact.getName());
//根据Item中的控件Id向控件添加事件监听
holder.setOnClickListener(R.id.ivPhone, new View.OnClickListener() {
@Override
public void onClick(View v) {
//自定义的代码
}
});
}
}