博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
XCoreRecyclerAdapter:更好用的Adapter For RecyclerView
阅读量:6332 次
发布时间:2019-06-22

本文共 11822 字,大约阅读时间需要 39 分钟。

XCoreRecyclerAdapter:一种通用的Adapter For RecyclerView

背景

每当我们使用RecyclerView写一个列表的时候,都需要写类似的如下代码:

...    mTestRv = (RecyclerView) view.findViewById(R.id.test_home_rv);    mTestRecyclerAdapter = new TestRecyclerAdapter(context);    mLinearLayoutManager = new LinearLayoutManager(context);    mTestRv.setLayoutManager(mLinearLayoutManager);    mTestRv.setAdapter(mTestRecyclerAdapter);    ...

那么,我们一般必不可少的是写一个Adapter,比如,为了支持多种类型,我们需要重写getItemViewType、onCreateViewHolder、onBindViewHolder等方法。比如:

public class TestRecyclerAdapter extends RecyclerView.Adapter
{ ... @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = null; switch (viewType) { case Type.TYPE_HEADER: view = LayoutInflater.from(mContext).inflate(R.layout.card_header, parent, false); return new HeaderViewHolder(view); case Type.TYPE_HIS_HEAD: view = LayoutInflater.from(mContext).inflate(R.layout.his_header, parent, false); return new HeaderHisViewHolder(view); ... default: break; } return new HeaderViewHolder(new RelativeLayout(mContext)); } @Override public void onBindViewHolder(ViewHolder holder, int position) { switch (getItemViewType(position)) { case Type.TYPE_HEADER: HeaderViewHolder headerViewHolder = (HeaderViewHolder) holder; headerViewHolder.bindView(mDataSet.get(position)); break; case Type.TYPE_HIS_HEAD: HeaderHisViewHolder headerHisViewHolder = (HeaderHisViewHolder) holder; headerHisViewHolder.bindView(mDataSet.get(position), mOnHeaderItemClickListener); break; ... default: break; } } @Override public int getItemViewType(int position) { Data data = mDateSet.get(position); String type = data.getType(); if("xxx".equals(type)){ return Type.TYPE_HEADER; }else if("xxxxx".equals(type)){ return Type.TYPE_HIS_HEAD; }else if(){ ... } ... }}

按照上述写法,每当我们需要增加一种类型的时候,都需要修改TestRecyclerAdapter的代码,在onCreateViewHolder等方法中添加对应的代码。后来大家觉得这个挺烦的,然后就把onCreateViewHolder中的switch语句放到工厂类当中,这一定层度上缓解了修改Adapter的频率。那么,我们能不能写一个相对通用的Adapter呢?

封装通用的插件式Adapter

我们希望做到如下目标:

  • 1).Adapter通用化,无需每次新建Adapter
  • 2).Item(Cell)的组件是插件式的,解耦,并可复用

用代码描述为:

...    //创建通用的Adapter    mXCoreRecyclerAdapter = new XCoreRecyclerAdapter(context);    //Adapter注册item组件    mXCoreRecyclerAdapter.registerItemUIComponent(new TodoItemComponent())                .registerItemUIComponent(new TestItemComponent());    //设置数据源,完成展示    mXCoreRecyclerAdapter.setDataSet(List
dataSet) ...

插件式的通用XCoreRecyclerAdapter的原理图如下:

XCoreRecyclerAdapter

每当我们需要添加一个新的类型时,只需要一下几步:

  • 1.新建一个TodoItemUIComponent组件,继承自XCoreItemUIComponent

    实现对应的方法;
  • 2.注册新增的组件TodoItemUIComponent

    调用XCoreRecyclerAdapter的registerItemUIComponent方法即可注册。
  • 3.数据源实现IDataComponent接口
    getViewType和组件TodoItemUIComponent的getViewType匹配即可;

这样,每次新增一种新的类型的Item时,无需修改Adapter的代码。并且,Item的组件是可复用的。

那么具体怎么设计的呢?

数据源

首先对数据源进行抽象:在Adapter列表中,需要根据数据源Data的不同类型,选择不同的ViewHolder。所以,数据源必须有一个getType的方法。

/**     * 数据源必须实现的接口     */    public interface IDataComponent {        String getViewType();    }

Item组件 ItemUIComponent

ItemUIComponent组件负责某一类type的管理。为了做到插件式,它必须实现的方法有:

  • onCreateView方法
    该方法是用于生成Item的根View的。当Adapter调用onCreateViewHolder时,该方法会被调用。注意,子View的初始化,不要写在onCreateView中。需要写在onViewCreated方法中。
  • onViewCreated方法
    创建完ItemComponent之后,就会立即回调该方法,View的初始化请写在这里。
  • getViewType方法
    该方法是为了和数据源进行关联的,数据源的getViewType方法和组件的getViewType方法的值一致时,即完成匹配。
  • bindView方法
    该方法会在Adapter回调onBindViewHolder
public class TodoItemComponent extends XCoreItemUIComponent {    @Override    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container) {        //TODO 在这里指定item组件的布局        return inflater.inflate(R.layout.todo_item_layout,container,false);    }    @Override    public void onViewCreated(View view) {        //TODO 在这里写View初始化        view.findViewById();        ...    }    @Override    public String getViewType() {        //与数据源的getViewType关联        return TodoItemComponent.class.getSimpleName();    }    @Override    public void bindView(IXCoreComponent coreComponent,                         XCoreRecyclerAdapter coreRecyclerAdapter,                         XCoreRecyclerAdapter.IDataComponent data,                         int pos) {        //TODO 在这里写绑定逻辑    }}

数据源和Item组件都已经定义好,那么,核心的XCoreRecyclerAdapter源码应该怎么做呢?

XCoreRecyclerAdapter源码

package com.github.nuptboyzhb.xcore.adapter;import android.content.Context;import android.support.v7.widget.RecyclerView;import android.text.TextUtils;import android.util.SparseArray;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import com.github.nuptboyzhb.xcore.components.IXCoreComponent;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;/** * @version mochuan.zhb on 2016/8/9. * @Author Zheng Haibo * @Blog github.com/nuptboyzhb * @Company Alibaba Group * @Description 通用的Adapter for RecyclerView */public class XCoreRecyclerAdapter extends RecyclerView.Adapter
{ private IXCoreComponent mIXCoreComponent;//外层UI组件 private List
mDataSet = new ArrayList
();//数据源 private SparseArray
mConfigurationSparseArray = new SparseArray
();//集合:type对应的Item组件 private Map
mViewTypeMap = new HashMap
();//type的string和int映射 public XCoreRecyclerAdapter() { } public XCoreRecyclerAdapter(IXCoreComponent mIXCoreComponent) { this.mIXCoreComponent = mIXCoreComponent; } @Override public CommonViewHolder onCreateViewHolder(ViewGroup viewGroup, int type) { //根据数据类型获取对应的item组件 XCoreItemUIComponent XCoreItemUIComponent = mConfigurationSparseArray.get(type); if (XCoreItemUIComponent == null) {//如果未获取到,展示空item return getDefaultViewHolder(viewGroup.getContext()); } try { //使用item组件创建一个新的View View view = XCoreItemUIComponent.onCreateView(LayoutInflater.from(viewGroup.getContext()), viewGroup); //使用View构建内部的ViewHolder CommonViewHolder commonViewHolder = new CommonViewHolder(view); //创建一个新的Item组件 XCoreItemUIComponent realItem = XCoreItemUIComponent.getClass().newInstance(); //将创建的View设置到真是的Item组件中 realItem.setItemView(view); //使用内部ViewHolder commonViewHolder.setXCoreItemUIComponent(realItem); return commonViewHolder; } catch (Throwable t) { t.printStackTrace(); } return getDefaultViewHolder(viewGroup.getContext()); } @Override public void onBindViewHolder(CommonViewHolder baseViewHolder, int pos) { baseViewHolder.bindView(mIXCoreComponent, this, mDataSet.get(pos), pos); } @Override public int getItemViewType(int position) { IDataComponent item = mDataSet.get(position); Integer integer = mViewTypeMap.get(item.getViewType()); if (integer == null) { return -1; } return integer; } @Override public int getItemCount() { if (mDataSet != null) { return mDataSet.size(); } return 0; } /** * 获取Adapter的数据源 * * @return */ public List
getDataSet() { return mDataSet; } /** * 设置Adapter的数据源 * * @param dataSet */ public void setDataSet(List
dataSet) { this.mDataSet = dataSet; notifyDataSetChanged(); } /** * get the error view holder * * @param context * @return */ protected CommonViewHolder getDefaultViewHolder(Context context) { return new CommonViewHolder(new View(context)); } /** * get the unique int type * * @param name * @return */ private int getUniqueIntType(String name) { if (TextUtils.isEmpty(name)) { return -1; } int type = name.hashCode(); while (true) { XCoreItemUIComponent old = mConfigurationSparseArray.get(type); if (old != null) { String oldName = old.getViewType(); if (!name.equals(oldName)) { type = type + 1; } else { return type; } } else { return type; } } } /** * 注册Item组件 * * @param XCoreItemUIComponent * @return */ public XCoreRecyclerAdapter registerItemUIComponent(XCoreItemUIComponent XCoreItemUIComponent) { if (XCoreItemUIComponent == null || TextUtils.isEmpty(XCoreItemUIComponent.getViewType())) { return this; } int viewTypeInt = getUniqueIntType(XCoreItemUIComponent.getViewType()); mViewTypeMap.put(XCoreItemUIComponent.getViewType(), viewTypeInt); mConfigurationSparseArray.put(viewTypeInt, XCoreItemUIComponent); return this; } /** * 注销配置 * * @param XCoreItemUIComponent * @return */ public XCoreRecyclerAdapter unregisterItemUIComponent(XCoreItemUIComponent XCoreItemUIComponent) { if (XCoreItemUIComponent == null || TextUtils.isEmpty(XCoreItemUIComponent.getViewType())) { return this; } int index = mConfigurationSparseArray.indexOfValue(XCoreItemUIComponent); if (index == -1) { return this; } mConfigurationSparseArray.remove(index); return this; } /** * 数据源必须实现的接口 */ public interface IDataComponent { String getViewType(); } /** * 使用CommonViewHolder代理XCoreItemUIComponent组件 */ public static class CommonViewHolder extends RecyclerView.ViewHolder { private XCoreItemUIComponent XCoreItemUIComponent; public void setXCoreItemUIComponent(XCoreItemUIComponent XCoreItemUIComponent) { this.XCoreItemUIComponent = XCoreItemUIComponent; } public XCoreItemUIComponent getXCoreItemUIComponent() { return XCoreItemUIComponent; } public CommonViewHolder(View itemView) { super(itemView); } public void bindView(IXCoreComponent mIXCoreComponent, XCoreRecyclerAdapter XCoreRecyclerAdapter, XCoreRecyclerAdapter.IDataComponent data, int pos) { if (XCoreItemUIComponent == null) { return; } XCoreItemUIComponent.bindView(mIXCoreComponent, XCoreRecyclerAdapter, data , pos); } public void onViewDetachedFromWindow() { if (XCoreItemUIComponent != null) { XCoreItemUIComponent.onViewDetachedFromWindow(); } } } @Override public void onViewDetachedFromWindow(CommonViewHolder holder) { super.onViewDetachedFromWindow(holder); holder.onViewDetachedFromWindow(); }}

XCoreItemUIComponent源码

package com.github.nuptboyzhb.xcore.adapter;import android.support.annotation.Nullable;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import com.github.nuptboyzhb.xcore.components.IXCoreComponent;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;/** * @version mochuan.zhb on 2016/8/12. * @Author Zheng Haibo * @Blog github.com/nuptboyzhb * @Company Alibaba Group * @Description item component 抽象类 */public abstract class XCoreItemUIComponent implements IXCoreComponent {    /**     * 创建View     *     * @param inflater     * @param container     * @return     */    public abstract View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container);    /**     * 在此做View的初始化操作     *     * @param view     */    public abstract void onViewCreated(View view);    /**     * item组件支持的ViewType,与IDataComponent的getViewType对应     *     * @return     */    public abstract String getViewType();    /**     * 绑定数据-频繁回调     *     * @param coreComponent       外出UI组件     * @param coreRecyclerAdapter Adapter     * @param data                对应的数据源     * @param pos                 item所在列表的位置     */    public abstract void bindView(IXCoreComponent coreComponent,                                  XCoreRecyclerAdapter coreRecyclerAdapter,                                  XCoreRecyclerAdapter.IDataComponent data,                                  int pos);    /**     * item组件销毁时调用     */    public abstract void onViewDetachedFromWindow();    //必须有无参数的构造函数    public View itemView;    public void setItemView(View itemView) {        this.itemView = itemView;        onViewCreated(itemView);    }    }

后续

本篇博客主要是介绍通用的XCoreRecyclerAdapter引擎,极大提高了Adapter的复用率,让开发集中把精力集中在必要的业务代码上,提高开发效率。另外,与XCoreRecyclerAdapter引擎相配套的还有UI组件化、数据控制框架XCoreRedux、数据绑定等。请参考下一遍博客:《Android Redux实践与UI组件化:XCoreRedux框架》(ing...)

转载地址:http://nkdoa.baihongyu.com/

你可能感兴趣的文章
自制操作系统Antz day08——实现内核 (中) 扩展内核
查看>>
poj-1056-IMMEDIATE DECODABILITY(字典)
查看>>
阿里云容器Kubernetes监控(二) - 使用Grafana展现Pod监控数据
查看>>
区块链应用 | 不知道什么时候起,满世界都在谈区块链的事情
查看>>
小程序爆红 专家:对简单APP是巨大打击
查看>>
FarBox--另类有趣的网站服务【转】
查看>>
在非纯色背景上,叠加背景透明的BUTTON和STATIC_TEXT控件
查看>>
Distributed2:Linked Server Login 添加和删除
查看>>
海量数据处理相关面试问题
查看>>
Python-time
查看>>
Java中取两位小数
查看>>
RTX发送消息提醒实现以及注意事项
查看>>
使用 ftrace 调试 Linux 内核【转】
查看>>
唯一聚集索引上的唯一和非唯一非聚集索引
查看>>
Spark新愿景:让深度学习变得更加易于使用——见https://github.com/yahoo/TensorFlowOnSpark...
查看>>
linux磁盘配额
查看>>
NFS文件共享服务器的搭建
查看>>
%r 和 %s 该用哪个?
查看>>
小公司职场不是“切糕”
查看>>
play工程部署到云服务器
查看>>