美文网首页Android开发Android开发经验谈Android技术知识
RecyclerAdapter简约封装 别辜负Java设计者的良

RecyclerAdapter简约封装 别辜负Java设计者的良

作者: wishes丶啊 | 来源:发表于2018-05-03 17:18 被阅读177次

阅读本文需要了解RecyclerView的基本使用,和Java泛型知识。
本文主要就是把RecyclerView.Adapter的使用抽象成只需实现一个方法。

首先看看一般使用RecyclerView.Adapter的写法。

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyHolder> {
  //数据
  List<Person> mData;

  //创建一条Item
  @Override
  public MyHolder onCreateViewHolder(ViewGroup parent,int viewType) {
      Context context=parent.getContext();  //获取上下文
      //获取Inflater对象
      LayoutInflater inflater = LayoutInflater.from(context);
      //把布局文件转换成View对象
      View view = inflater.inflate(layoutRes, parent, false);
      //返回Holder view传递给MyHolder构造方法,所以下面MyHolder构造方法中的参数就是这个view
      return MyHolder(view);
  }

  //绑定数据
  @Override
  public void onBindViewHolder(MyHolder holder,int position) {
    Person person = mData.get(position);
    (MyHoler)holder.name.setText(person.getName());
  }

  //获取数据量 返回多少 RecyclerView就显示多少个
  @Override
  public int getItemCount() {
    return mData.size();
  }

  //自己的ViewHolder
  public class MyHolder extends RecyclerView.ViewHolder {
    TextView name;
    public MyHolder(View itemView) {
          super(itemView);
          name = item.findViewById(R.id.name);
    }
  }
}

大致都是这样写的Adapter,很多地方都要RecylerAdapter,就新建很多RecylerAdapter。这是非常繁琐的。分析上面的代码,其实有很多共同之处,我们可以对共同之处进行封装。

以下几点是共同的
1.onCreateViewHolde()方法中流程都是一样的
2.onBindViewHolder()都是先要获取单个数据
3.getItemCount()方法都是返回数据的长度
4.MyHolder中的findViewById();

以下几点不同,分别进行不同的处理方法
1.数据类型不一样,因为使用泛型,这个问题不要考虑。
2.对数据的操作不一样,可以抽象一个方法给实现类自己去处理。
3.Item布局资源不一样,可以让实现类传递给父类,反正都是进行相同的操作。

然后其他的就差不多了,分析完成之后就可以开写了。
首先定义一个抽象类继承RecylerView.Adapter,并且使用泛型。因为目前不需要知道数据的类型。

public abstract class CommonAdapter<T> extend RecyclerView.Adapter<CommonAdapter.CommonHolder>{
  private List<T> mData;  //数据 
  private int mItemLayoutRes;  //Item布局资源id

  //构造方法  子类需要传递数据和item布局Id
  public CommonAdapter(List<T> data, int itemLayoutRes){
    mData  =  data;
    mItemLayoutRes  =  itemLayoutRes;
  }

  //设置数据方法
  public void setData(List<T> data) {
    this.mData = data;
  }

  @Override
  public CommonHolder onCreateViewHolder(ViewGroup parent,int viewType){
    //此段代码都是相同的,只是item布局资源不同,然实现类传递进来
    Context context = parent.getContext();
    LayoutInflater inflater = LayoutInflater.from(mContext);
    View view = inflater.inflate(mItemLayoutRes, parent, false);
    return new CommonHolder(view,mContext);
  }

  @Override
  public void onBindViewHolder(final CommonHolder holder, int position) {
    T t = mData.get(position);  //获取单个资源
    if(t!=null){   //如果数据为空就不传递给实现类
      bindData(holder,t);  //给实现类Holder和数据,让实现类对数据处理
    }
  }

  @Override
  public  int getItemCount(){
    //返回数据长度
    return mData.size();
  }    
  
  //实现类需要实现的方法
  protected abstract void bindData(CommonHolder holder, T t);
}

这样大致RecylerView.Adapter就抽象好了,接下来写RecyclerView.ViewHolder,也使用泛型,并且设定一个限定,因为findViewById获取的肯定是View获取其子类。
SparseArray集合用来保存item里面的控件对象。之所以使用集合,是因为recyclerView是一种复用的控件,不把这些控件保存起来的话,重新绘制的话每次都要调用findViewById,这样效率会很低。保存起来直接可以从SparseArray中获取。而且SparseArray是一种轻量级的集合框架。
其中有一个从view中获取控件的方法,两个对集合的操作方法,若干个对控件赋值方法。

public class ComonHolder<V extends View> extends RecyclerView.ViewHolder{
  private View view;  //item的布局文件
  private SparseArray<V> sparseArray = new SparseArray<>();  //Item集合

  CommonHolder(View itemView, Context context) {
        super(itemView);
        view = itemView;  //接收传递进来的view对象,这个view就是item展示的布局对象
    }

    //从view中获取控件
    protected V findViewById(int resId) {
        return view.findViewById(resId);
    }

    //put方法
    public void putView(int viewId){
      sparseArray.put(ViewId, findViewById(ViewId));
    }

    //get方法
    public V getView(int viewId){
      V v = sparseArray.get(ViewId);  //首先从集合中获取
      if (v != null) {    //如果获取到数据 则直接返回
            return v;
        } else {        //如果集合中没有,则往集合中添加
            putView(ViewId);
        }
        return sparseArray.get(ViewId);  //添加之后再获取
    }

    //设置文字内容
    public void setText(int viewId,String content){
      ((TextView) getView(ViewId)).setText(content);
    }

    //设置图片
    public void setImage(int ViewId, int resId) {
        ((ImageView) getView(ViewId)).setImageResource(resId);
    }
}

好啦,Holder也封装完成了。接下来看看使用效果,随便新建一个类,继承CommonAdapter来看看效果。泛型定为Person是因为我的数据类型是Person。

public class PersonAdapter extends CommonRecyclerAdapter<Person> {

   //数据传给父类
  public ShowGameAdapter(List<GameBean> data,int layoutRes) {
      super(data,layoutRes);
  }

  @Override
  protected void bindData(CommonHolder holder, GameBean gameBean) {
      holder.setText(R.id.person_name, gameBean.getGameName());
      holder.setImage(R.id.person_image, gameBean.getImage());
      //此处也可以注册单击事件
  }
}

本来要写长的代码,被我一顿花里胡哨我自己都看不懂的操作变得只需要写这么点代码。使用这个适配器效果:

  public List<Person> mDate;
  //...mData初始化 RecyclerView初始化
  //适配器初始化
  PersonAdapter adapter = new PersonAdapter(mData,R.layout.item_recycler);
  recycler.setAdapter(adapter);

终于写完了。大家还是多使用Java设计者提供便利之处,不要辜负Java设计者的用心良苦。一个程序要不应该只管实现功能,而更应该要有梦想有情怀,代码要精炼简洁,要有乐于共享的精神。当然,还得有一颗向上的心。如果您发现了错误之处欢迎指正,大家一起进步。

相关文章

网友评论

  • ZCJ风飞:这种不注重扩展的封装程度越高,适用情况就会差一些
    wishes丶啊:@ZCJ风飞 是的,这是根据我目前业务写的,扩展性确实不高。以后还会继续改进的
  • IT人故事会:写得太好了。老铁,动动手指收藏了
    wishes丶啊:大哥,帮忙点个赞啊:joy:

本文标题:RecyclerAdapter简约封装 别辜负Java设计者的良

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