BaseRecyclerViewAdapterHelper 开源项目之 BaseMultiItemQuickAdapter 实现多类型源码学习

本贴最后更新于 2964 天前,其中的信息可能已经时移世异

version:2.8.5

今天我们来看下 BaseRecyclerViewAdapterHelper 是如何实现多布局的。

首先我们要实现多类型布局,我们的 adapter 不再是继承自 BaseQuickAdapter 类,而是继承自其的子类 BaseMultiItemQuickAdapter。而且数据源类型需要继承自 MultiItemEntity,MultiItemEntity 是一个接口,代码很少:

package com.chad.library.adapter.base.entity; /** * https://github.com/CymChad/BaseRecyclerViewAdapterHelper */ public interface MultiItemEntity { int getItemType(); }

其主要用意是我们的数据源继承 MultiItemEntity,这样子,我们可以在数据源中动态的返回一个 int 类型的数值(代表某一类型的 item),大家可以想一下,我们在渲染 viewholder 的时候,如果想实现多类型的 viewholder,而 viewholder 的类型展示又跟所需绑定的数据息息相关,那么如果我们在数据源中提供一种确定 viewholder 类型的能力,理论上是不是就可以达到我们要的效果了?我们带着这样的一个假设继续往下看。而这个 BaseMultiItemQuickAdapter 是何许人也,是如何实现多类型布局的呢?我们来看下源码:

package com.chad.library.adapter.base; import android.support.annotation.LayoutRes; import android.util.SparseArray; import android.view.ViewGroup; import com.chad.library.adapter.base.entity.MultiItemEntity; import java.util.List; /** * https://github.com/CymChad/BaseRecyclerViewAdapterHelper */ public abstract class BaseMultiItemQuickAdapter extends BaseQuickAdapter<T, K> { /** * layouts indexed with their types */ private SparseArray layouts; private static final int DEFAULT_VIEW_TYPE = -0xff; /** * Same as QuickAdapter#QuickAdapter(Context,int) but with * some initialization data. * * @param data A new list is created out of this one to avoid mutable list */ public BaseMultiItemQuickAdapter( List data) { super( data); } @Override protected int getDefItemViewType(int position) { Object item = mData.get(position); if (item instanceof MultiItemEntity) { return ((MultiItemEntity)item).getItemType(); } return DEFAULT_VIEW_TYPE; } protected void setDefaultViewTypeLayout(@LayoutRes int layoutResId) { addItemType(DEFAULT_VIEW_TYPE, layoutResId); } @Override protected K onCreateDefViewHolder(ViewGroup parent, int viewType) { return createBaseViewHolder(parent, getLayoutId(viewType)); } private int getLayoutId(int viewType) { return layouts.get(viewType); } protected void addItemType(int type, @LayoutRes int layoutResId) { if (layouts == null) { layouts = new SparseArray<>(); } layouts.put(type, layoutResId); } }

源码不多:

字段解析:

1、存储我们的布局资源的 ids

private SparseArray layouts;

2、缺省的布局类型值,当使用多布局时,在渲染 viewholder 的时候类型址不是我们配置的类型值中,就会使用这个。

private static final int DEFAULT_VIEW_TYPE = -0xff;

接下来,我们以一个 BaseMultiItemQuickAdapter 的创建过程来分析代码:

之前我们分析了 BaseQuickAdapter 的代码,其执行过程是一样的,我们实现多布局功能的切入口无非是

1、在执行 getItemViewType 时的能够根据我们的数据源返回对应的布局类型值。

2、在 onCreateDefViewHolder 能够正确拿到类型值进行 viewholder 的渲染。

3、我们在 onBindViewHolder 中根据传递给我们的数据源中接口定义的 getItemViewType 方法返回的类型值来确定当前的 viewholder 是什么类型的,需要绑定什么数据。

(注:之前分析了 adapter 的加载数据时的生命周期方法:getItemViewType->onCreateDefViewHolder->onBindViewHolder,如果不大清楚可以看下前面的文章)

所以,我们在 BaseMultiItemQuickAdapter 里面重写了 getDefItemViewType 方法,为什么时重写 getDefItemViewType 方法而不是 getItemViewType 方法呢?这可不是我糊弄你,因为我们在 BaseQuickAdapter 里面重写了 getItemViewType 方法,而在 getItemViewType 方法里调用了 getDefItemViewType 方法来回去类型值,该方法也在之前的分析 BaseQuickAdapter 源码的文章中分析了的。
重写之后做了什么呢?看代码:

@Override protected int getDefItemViewType(int position) { Object item = mData.get(position); if (item instanceof MultiItemEntity) { return ((MultiItemEntity)item).getItemType(); } return DEFAULT_VIEW_TYPE; }

很简单,因为我们的数据源实现了 MultiItemEntity 接口。直接判断该 position 的数据是不是实现了 MultiItemEntity 接口,是调用接口的 getItemType 方法返回类型值,不是返回默认类型值。
第一步返回类型值的代码改造完成了,接下来第二部就是根据类型值渲染 viewholder。BaseMultiItemQuickAdapter 直接重写了 onCreateDefViewHolder 方法来实现该扩展:

@Override protected K onCreateDefViewHolder(ViewGroup parent, int viewType) { return createBaseViewHolder(parent, getLayoutId(viewType)); }

代码很简单,从我们存储布局缓存的字段中根据 viewType 返回对象的布局资源的 ids。
所以 BaseMultiItemQuickAdapter 还给我们包装了一个 addItemType 方法:

protected void addItemType(int type, @LayoutRes int layoutResId) { if (layouts == null) { layouts = new SparseArray<>(); } layouts.put(type, layoutResId); }

该方法很简单,就是将不同的布局资源的 ids 和对应的类型值存储起来。
所以我们的创建多布局的时候,需要的构造函数中调用 addItemType 来添加不同的布局资源
最后一步,绑定数据;一般绑定数据实在 onBindViewHolder 中实现的,而我们的 BaseRecyclerViewAdapterHelper 对其进行了包装,提供了一个 convert 方法,所以我们只需要在 convert 方法中根据数据源数据节点的类型值判断绑定的是那个布局的数据即可。
总结:理解了 adapter 加载数据的生命周期方法的执行顺序很重要(getItemViewType->onCreateDefViewHolder->onBindViewHolder)。

只要控制 viewType 的返回、viewholder 的渲染。viewholder 数据的绑定即可。

  • Android

    Android 是一种以 Linux 为基础的开放源码操作系统,主要使用于便携设备。2005 年由 Google 收购注资,并拉拢多家制造商组成开放手机联盟开发改良,逐渐扩展到到平板电脑及其他领域上。

    336 引用 • 324 回帖 • 3 关注
  • int
    12 引用 • 18 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • someone

    你好。请问可以发个 多类型 demo看看么? 谢谢了

  • someone

    你好,这个在BaseRecyclerViewAdapterHelper的官网有demo apk哦

  • someone

    你好,这个在BaseRecyclerViewAdapterHelper的官网有demo apk哦

  • someone

    你好,这个在BaseRecyclerViewAdapterHelper的官网有demo apk哦

推荐标签 标签

  • Node.js

    Node.js 是一个基于 Chrome JavaScript 运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络应用。Node.js 使用事件驱动, 非阻塞 I/O 模型而得以轻量和高效。

    139 引用 • 269 回帖 • 2 关注
  • Sandbox

    如果帖子标签含有 Sandbox ,则该帖子会被视为“测试帖”,主要用于测试社区功能,排查 bug 等,该标签下内容不定期进行清理。

    440 引用 • 1238 回帖 • 596 关注
  • 机器学习

    机器学习(Machine Learning)是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。

    77 引用 • 37 回帖
  • Facebook

    Facebook 是一个联系朋友的社交工具。大家可以通过它和朋友、同事、同学以及周围的人保持互动交流,分享无限上传的图片,发布链接和视频,更可以增进对朋友的了解。

    4 引用 • 15 回帖 • 440 关注
  • HHKB

    HHKB 是富士通的 Happy Hacking 系列电容键盘。电容键盘即无接点静电电容式键盘(Capacitive Keyboard)。

    5 引用 • 74 回帖 • 519 关注
  • Postman

    Postman 是一款简单好用的 HTTP API 调试工具。

    4 引用 • 3 回帖 • 1 关注
  • Laravel

    Laravel 是一套简洁、优雅的 PHP Web 开发框架。它采用 MVC 设计,是一款崇尚开发效率的全栈框架。

    19 引用 • 23 回帖 • 739 关注
  • HTML

    HTML5 是 HTML 下一个的主要修订版本,现在仍处于发展阶段。广义论及 HTML5 时,实际指的是包括 HTML、CSS 和 JavaScript 在内的一套技术组合。

    108 引用 • 295 回帖 • 1 关注
  • Kafka

    Kafka 是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据。 这种动作(网页浏览,搜索和其他用户的行动)是现代系统中许多功能的基础。 这些数据通常是由于吞吐量的要求而通过处理日志和日志聚合来解决。

    36 引用 • 35 回帖 • 3 关注
  • SpaceVim

    SpaceVim 是一个社区驱动的模块化 vim/neovim 配置集合,以模块的方式组织管理插件以
    及相关配置,为不同的语言开发量身定制了相关的开发模块,该模块提供代码自动补全,
    语法检查、格式化、调试、REPL 等特性。用户仅需载入相关语言的模块即可得到一个开箱
    即用的 Vim-IDE。

    3 引用 • 31 回帖 • 111 关注
  • C++

    C++ 是在 C 语言的基础上开发的一种通用编程语言,应用广泛。C++ 支持多种编程范式,面向对象编程、泛型编程和过程化编程。

    108 引用 • 153 回帖
  • RabbitMQ

    RabbitMQ 是一个开源的 AMQP 实现,服务器端用 Erlang 语言编写,支持多种语言客户端,如:Python、Ruby、.NET、Java、C、PHP、ActionScript 等。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。

    49 引用 • 60 回帖 • 353 关注
  • C

    C 语言是一门通用计算机编程语言,应用广泛。C 语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。

    86 引用 • 165 回帖
  • Pipe

    Pipe 是一款小而美的开源博客平台。Pipe 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    134 引用 • 1127 回帖 • 107 关注
  • Docker

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的操作系统上。容器完全使用沙箱机制,几乎没有性能开销,可以很容易地在机器和数据中心中运行。

    497 引用 • 934 回帖
  • SQLite

    SQLite 是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是全世界使用最为广泛的数据库引擎。

    4 引用 • 7 回帖
  • Markdown

    Markdown 是一种轻量级标记语言,用户可使用纯文本编辑器来排版文档,最终通过 Markdown 引擎将文档转换为所需格式(比如 HTML、PDF 等)。

    172 引用 • 1538 回帖
  • FFmpeg

    FFmpeg 是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。

    23 引用 • 32 回帖 • 7 关注
  • WiFiDog

    WiFiDog 是一套开源的无线热点认证管理工具,主要功能包括:位置相关的内容递送;用户认证和授权;集中式网络监控。

    1 引用 • 7 回帖 • 615 关注
  • TextBundle

    TextBundle 文件格式旨在应用程序之间交换 Markdown 或 Fountain 之类的纯文本文件时,提供更无缝的用户体验。

    1 引用 • 2 回帖 • 82 关注
  • Maven

    Maven 是基于项目对象模型(POM)、通过一小段描述信息来管理项目的构建、报告和文档的软件项目管理工具。

    188 引用 • 319 回帖 • 239 关注
  • OneNote
    1 引用 • 3 回帖
  • Excel
    31 引用 • 28 回帖 • 1 关注
  • WebClipper

    Web Clipper 是一款浏览器剪藏扩展,它可以帮助你把网页内容剪藏到本地。

    3 引用 • 9 回帖 • 1 关注
  • 钉钉

    钉钉,专为中国企业打造的免费沟通协同多端平台, 阿里巴巴出品。

    15 引用 • 67 回帖 • 265 关注
  • Angular

    AngularAngularJS 的新版本。

    26 引用 • 66 回帖 • 561 关注
  • Logseq

    Logseq 是一个隐私优先、开源的知识库工具。

    Logseq is a joyful, open-source outliner that works on top of local plain-text Markdown and Org-mode files. Use it to write, organize and share your thoughts, keep your to-do list, and build your own digital garden.

    7 引用 • 69 回帖 • 5 关注