androidAndroid UIAndroid知识

Android中recycleview的adapter封装

2017-04-28  本文已影响586人  昵称真难选

原文出自王艳涛的专栏转载请注明出处!

概述

android开发中经常用到ListView、RecycleView等列表控件,为了增强这类控件的显示和灵活应用,需要自己继承和重写android提供的adapter类。但是android提供的adapter都比较抽象,重写时会产生大量重复代码,所以进行封装后再使用是一个很必要的步骤。
既然是封装就要达到下面两个要求:

  1. 代码:尽量减少重复代码;
  2. 功能:能够方便的获取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复用主要有三个方面的因素:

  1. 每次使用adapter时,都需要传进一个集合数据,类型是自定义的,如List中的MyData等,所以进行封装成基类adapter时,应该消除基类对集合数据类型敏感性,解决方案为:引入泛型。
  2. Myholder作为adapter的内部类,不同的adapter一般需要不同的holder,所以内部类的形式影响adapter的复用,解决方案为:将holder抽出,单独封装为一个holder基类。
  3. 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) {
        //自定义的代码
      }
    });
  }
}
上一篇下一篇

猜你喜欢

热点阅读