美文网首页androidAndroid UIAndroid知识
Android中recycleview的adapter封装

Android中recycleview的adapter封装

作者: 昵称真难选 | 来源:发表于2017-04-28 18:05 被阅读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) {
            //自定义的代码
          }
        });
      }
    }
    

    相关文章

      网友评论

        本文标题:Android中recycleview的adapter封装

        本文链接:https://www.haomeiwen.com/subject/qadazttx.html