MultiType多列表框架思想

  • 前言
  • MultiType 的特性
  • 常用写法
  • 核心思想
  • 源码
  • 用法

前言

本文是我的笔记以及Android的知识积累;

MultiType 的特性

  1. 轻盈,整个类库只有 14 个类文件,aar 或 jar 包大小只有 13 KB
  2. 周到,支持 data type <–> item view binder 之间 一对一 和 一对多 的关系绑定
  3. 灵活,几乎所有的部件(类)都可被替换、可继承定制,面向接口 / 抽象编程
  4. 纯粹,只负责本分工作,专注多类型的列表视图 类型分发,绝不会去影响 views 的内容或行为
  5. 高效,没有性能损失,内存友好,最大限度发挥 RecyclerView 的复用性
  6. 可读,代码清晰干净、设计精巧,极力避免复杂化,可读性很好,为拓展和自行解决问题提供了基础

这是对MultiType的特性的释义,可能用起来没有什么问题,但是要知道为什么,如何实现?请继续看…

常用写法

private Adapter extent RecyclerView.Adapter {

    # 数据源

    # 构造方法

    # onCreatViewHolder(...){}

    # onBindViewHodler(...){}

    # getItemCount(){}

    # getItemViewType(){}

}

实际写起来可能也没有什么大的问题,但是对于多ItemType的情况下,我们需要控制不同的type类型,在后续的需要、业务改动中,可能还需要调整,时间长了,即使是自己所写的代码也会感到无从下手,MultiType就应运而生。

核心思想

  1. 扩展 RecyclerView.Adapter 类,
    • 当前所有的数据存储
      • List data 保存所有的数据源
      • List itemDataClassName 保存所以数据源类型的 className (能够唯一标识的,存取规则保持一致即可)
      • List 保存所有对应与 itemData 管理类
    • 将视图、数据绑定操作放到 Manager 的具体实现类中去处理
    • 使用 List itemDataClassName 的下标指代 ItemType
  2. 扩展 RecyclerView.ViewHolder 类,可做一些功能的拓展
  3. ViewHolderManager 其主要职责:返回视图、处理数据与视图的绑定

其中比较新颖、有趣的想法:
- 所有的ItemType有数据类型集合中的下标所自行控制,这就让我们不用再关心不同position对应的itemType是多少的问题;
- register 操作,对列表所加载数据类型注册进 adapter

源码

结合上面的思想,精简出了3个java类,就可以基本实现:

/**
 * Adapter的主要实现。
 *
 * @author egan on 2018/4/20.
 * @date 2018/4/20 上午10:26.
 */
public class BaseAdapter extends RecyclerView.Adapter<BaseViewHolder> {

    // 数据源
    private List data = new ArrayList<>();

    // 保存 数据源类型
    private List dataTypes = new ArrayList<>();
    // 保存 数据源类型对应的 manager
    private List dataManagers = new ArrayList<>();

    @Override
    public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // 根据 viewType 获取 获取预订类型,>> manage >>> 获得ViewHolder
        // itemViewType 的值即对应 数据类型的下标
        return dataManagers.get(viewType).onCreateViewHolder(parent);
    }

    @Override
    public int getItemViewType(int position) {
        // return super.getItemViewType(position);
        Object o = data.get(position);
        // 根据数据对象去预订的类型中去获取对应
        return dataTypes.indexOf(o.getClass().getName());
    }

    @Override
    public void onBindViewHolder(BaseViewHolder holder, int position) {
        // itemViewType 的值即对应 数据类型的下标
        int index = getItemViewType(position);
        // 获取 Item 的数据
        Object itemData = data.get(position);
        // 获取 Item 数据类型对应的 manager
        ViewHolderManager itemViewHolderManager = dataManagers.get(index);
        itemViewHolderManager.onBindViewHolder(itemData, holder);
    }

    @Override
    public int getItemCount() {
        return this.data == null ? 0 : this.data.size();
    }

    // 将类型注册进入 adapter 中,表明该 adapter包含哪些类型
    public void register(Class o, ViewHolderManager manager) {
        if (dataTypes.contains(o.getName())) {
            dataManagers.set(dataTypes.indexOf(o.getName()), manager);
        } else {
            dataTypes.add(o.getName());
            dataManagers.add(manager);
        }
    }

    public void setData(List data) {
        this.data = data;
        notifyDataSetChanged();
    }
}
/**
 * 基本的 ViewHolder,用于自己的处理
 *
 * @author egan on 2018/4/20.
 * @date 2018/4/20 上午10:02.
 */
public class BaseViewHolder extends RecyclerView.ViewHolder {

    public BaseViewHolder(View itemView) {
        super(itemView);
    }

    public int getItemPosition() {
        return this.getAdapterPosition();
    }

}
/**
 * 其子类处理View视图的返回以及视图与数据的绑定.
 *
 * @author egan on 2018/4/20.
 * @date 2018/4/20 上午10:10.
 */
public abstract class ViewHolderManager<T> {

    public BaseViewHolder onCreateViewHolder(ViewGroup parent) {
        View itemView = LayoutInflater.from(parent.getContext()).inflate(getItemLayoutId(), parent, false);
        return new BaseViewHolder(itemView);
    }

    public abstract void onBindViewHolder(T t, BaseViewHolder viewHolder);

    @LayoutRes
    public abstract int getItemLayoutId();

    private  V findViewById(View itemView, @IdRes int viewId) {
        return itemView.findViewById(viewId);
    }

    protected  V findViewById(BaseViewHolder viewHolder, @IdRes int viewId) {
        return findViewById(viewHolder.itemView, viewId);
    }
}

用法

测试用实体类.

class Test1 {
    public Test1(String name) {
        this.name = name;
    }

    String name;
}

class Test2 {
    public Test2(int age) {
        this.age = age;
    }

    int age;
}
class Test1Manager extends ViewHolderManager {
    @Override
    public void onBindViewHolder(Test1 test1, BaseViewHolder viewHolder) {
        TextView text1 = findViewById(viewHolder, android.R.id.text1);
        TextView text2 = findViewById(viewHolder, android.R.id.text2);

        text1.setText("这是 Test 1");
        text2.setText("姓名 >>> " + test1.name);
    }

    @Override
    public int getItemLayoutId() {
        return android.R.layout.simple_list_item_2;
    }
}

class Test2Manager extends ViewHolderManager {
    @Override
    public void onBindViewHolder(Test2 test1, BaseViewHolder viewHolder) {
        TextView text1 = findViewById(viewHolder, android.R.id.text1);
        TextView text2 = findViewById(viewHolder, android.R.id.text2);

        text1.setText("这是 Test 2");
        text2.setText("年龄 >>> " + test1.age);
    }

    @Override
    public int getItemLayoutId() {
        return android.R.layout.simple_list_item_2;
    }
}

具体使用 Demo

// 伪造数据源
List allData = new ArrayList<>();
allData.add(new Test1("maka 1"));
allData.add(new Test1("maka 2"));
allData.add(new Test2(1));
allData.add(new Test2(2));

// 创建 Adapter 实例,并注册 Model 与 Manager 
BaseAdapter baseAdapter = new BaseAdapter();
baseAdapter.register(Test1.class, new Test1Manager());
baseAdapter.register(Test2.class, new Test2Manager());

// 绑定 RecyclerView 与 Adapter
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(baseAdapter);

// 刷新数据源
baseAdapter.setData(allData); 
  

                            
                        
                    
                    
                    

你可能感兴趣的:(Android之学习笔记)