Android RecyclerView —— 适配器封装探索

Android RecyclerView —— 基本使用

Android RecyclerView —— 自定义分割线

RecyclerView 适配器的编写

RecyclerView 如果需要填充数据,就必须使用到适配器。在一般情况下,我们定义一个适配器只需要定义一个类,然后集成 RecyclerView.Adapter 类,然后实现齐总的抽象的方法即可,如下,实现一个简单的适配器:

public class MyAdapter extends RecyclerView.Adapter {    private List dataList = new ArrayList<>();        @NonNull    @Override    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {        return new MyViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_layout,false));    }    @Override    public void onBindViewHolder(@NonNull MyViewHolder viewHolder, int i) {        viewHolder.setData(dataList.get(i));    }    @Override    public int getItemCount() {        return dataList.size();    }    static class MyViewHolder extends RecyclerView.ViewHolder {        public MyViewHolder(@NonNull View itemView) {            super(itemView);        }    }        public void setData(String itemData){        // 设置数据    }}

实现起来是比较简单的,代码量也不算太多,但是一个应用里面往往会有大量的列表,如果我们一个一个的都如此实现,就会有大量的重复代码。那么,对Adapter进行封装就很有必要了。

RecyclerView 适配器封装方式探索

对代码的封装有多种方式,那么,对RecyclerView 适配器的封装同样也有很多的方式。在这里,主要说一下两种封装方式:
1.抽取基类
思路:将多个 Adapter 中相同的代码抽取成基类,并且相关的事件(item 单击、长按等) 也封装到基类中,将不同的地方定义为抽象,由具体的子类来实现。这种方式是最容易想到的,同时也是比较常见的封装形式
思路解析:通过上的封装方式我们发现,每一个列表都需要绑定一个对应的 Adapter 类,然后创建一个或多个 RecyclerView.ViewHolder 类(一般为静态内部类)区分不同的 item 类型,这样虽然在一定程度上减少的代码量,不过有几个坏处:

① 我如果在后期需要在列表中增加一种item样式,那么就需要修改对应的 Adapter 类,新建一个内部 RecyclerView.ViewHolder 类,并在 AdapteronCreateViewHolder() 方法中返回以及 onBindViewHolder() 方法中判断以及设置具体数据。显然这种方式是不太友好的,因为他会修改我们以前的代码,尤其是当 Adapter 类的代码比较多时,更难修改并且更加容易出错;
② 因为在创建 RecyclerView.ViewHolder 类时,一般都是使用的内部类的形式,那么当应用中不同的列表中有多个完全一样的item类型时(他们属于不同的 RecyclerView,或者是多个 RecyclerView 都有不同的 item 类型,但是他们有部分 item 是完全一样的),那么也会直接在不同的 Adapter 中的创建多个相同的 RecyclerView.ViewHolder 内部类,这样导致相同的代码编写了多遍,而修改时,也需要修改多个类,增加量遗漏和发生错误的可能。

其实上面的两个问题也可以简单的归纳为两个字:耦合,每一个列表和对应的 Adapter 耦合在一起了,然后 Adapter 又和他下面的每一个 item 耦合在一起了,所以导致了问题的发生。

2.基于上面的两个问题,所以第二种方式主要就是对列表和 Adapter 以及 item 之间进行解耦
思路:首先我们看一下RecyclerView怎样显示list集合数据的,要将一个的数据填充到RecyclerView中,需要借助一个类,那就是 RecyclerView.Adapter 类,RecyclerView.Adapter 类中包含了具体列表的具体数据,每一条数据就是一个 item,那么可以用下图表示他们之间的关系:

通过图可以得知,其实 RecyclerView 只是要借助 RecyclerView.Adapter 类填充数据,而 RecyclerView.Adapter 和 item 之间的也没有必然联系,只是有包含关系,那么我们就可以使用如下的方式来进行解耦,如图:

思路解析:把Adapter剥离,将item作为一个最小单元添加到Adapter中,然后RecyclerView通过持有Adapter的对象来显示item数据。这样一来,当需要新的不同类型的item时,只需要新建一个item单元,然后调用Adapter的方法将item增加到Adapter中即可,而不需要修改Adapter的代码,同时,因为是将item作为一个单元,那么,应用中有相同的item类型时,也是可以共用的。

使用代码实现

抽取基类的方式有网上有很多写的非常好的文章和代码了,这了就不再使用代码来实现了。主要看看第二种解耦的代码实现。 可以直接进入 GitHub 下载代码

步骤说明:
首先,我们把每个item单元作为一个cell来看,定义一个接口 IRecyclerCell 并定义基本方法,然后提供一个默认的实现 abstract class RecyclerCell implements IRecyclerCell

其次,定义一个统一的 Adapter 类,RecyclerAdapter,他主要包含了对 item 单元 IRecyclerCell 的增删改等操作并刷新列表。

接着,因为 RecyclerView.Adapter 类的 onCreateViewHolder() 方法需要返回一个 RecyclerView.ViewHolder,所以我们封装一个统一的 ViewHolder叫做 RecyclerViewHolder,在这个类中使用 SparseArray 来保存item的字View,减少 findViewById() 操作,并提供对常见 view 的值进行设置、getView() 、item的单击事件、长按事件等监听。

最后,就是将这几个类关联起来。我们说了,这种方式主要是进行解耦,把每一个item作为一个cell来处理,所以我们应该对不同的item,来创建不同的 cell(当然新建的cell需要继承 RecyclerCell ,泛型表示该item的数据),现实其抽象方法,然后在页面中根据数据创建不同 cell 对象,添加到列表中,最后将cell对象列表设置到统一的Adapter —— RecyclerAdapter中就能实现数据的填充了。

下面三个方法是 RecyclerCell 实现类必须实现的方法:
getRecyclerItemType()方法很重要,尤其是对于一个列表中有多种item类型时,他的返回值就是用来区分不同item类型的标记,如果返回值一样,那表示item的类型一样,不同的列表中互不干扰
onCreateViewHolder()方法返回一个统一的 RecyclerViewHolder
onBindViewHolder() 方法绑定 holder

/** * 返回 item 类型,子类必须实现。并且添加到同一个 {@link RecyclerAdapter} 的不同 * {@link IRecyclerCell} 的 {@link #getRecyclerItemType()} 返回值必须不同
* 作用:用于在 {@link RecyclerAdapter} 中区分不同的 item 类型。 * * @return item 类型值,用于区分不同的 item 类型 */int getRecyclerItemType();T getItemData();/** * 创建 ViewHolder * * @param viewType 正常情况下该参数的值和 {@link #getRecyclerItemType()} 方法的返回值相等 */@NonNullRecyclerViewHolder onCreateViewHolder(@NonNull Context context, @NonNull ViewGroup parent, int viewType);/** * 绑定 holder,{@link RecyclerCell#itemData} 为 item 数据 */void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position, T itemData);

去 GitHub 下载代码

更多相关文章

  1. 解析android中的帮助、about、关于作者、HELP等提示页面
  2. Android(安卓)Material Design Snackbar Example
  3. Android(安卓)JNI实例代码(二)
  4. android 动态加载布局文件三种方法
  5. 《Android(安卓)JNI》05 在JNI中调用Java的函数
  6. Android(安卓)SQLiteOpenHelper
  7. Android(安卓)判断手机是否安装某个应用
  8. 安卓新技术学习资料整理 常更新哦~
  9. Android悬浮通知无效的问题

随机推荐

  1. Android开发7:单元测试
  2. Android开发神贴整理
  3. 在sd卡存储文件
  4. Android(安卓)Support Package 支撑包
  5. Android获得全局进程信息以及进程使用的
  6. Android(安卓)Studio 自定义Apk的名字
  7. Android(安卓)解决布局问题
  8. Android(安卓)BLE Gatt实现原理解析(未完)
  9. Android(安卓)获取设备各种信息以及其它
  10. Android(安卓)1.5: 飞行模式分析