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

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

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 回帖
  • int
    12 引用 • 18 回帖

相关帖子

欢迎来到这里!

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

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

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

  • someone

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

  • someone

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

  • someone

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

推荐标签 标签

  • Hexo

    Hexo 是一款快速、简洁且高效的博客框架,使用 Node.js 编写。

    22 引用 • 148 回帖 • 17 关注
  • NetBeans

    NetBeans 是一个始于 1997 年的 Xelfi 计划,本身是捷克布拉格查理大学的数学及物理学院的学生计划。此计划延伸而成立了一家公司进而发展这个商用版本的 NetBeans IDE,直到 1999 年 Sun 买下此公司。Sun 于次年(2000 年)六月将 NetBeans IDE 开源,直到现在 NetBeans 的社群依然持续增长。

    78 引用 • 102 回帖 • 701 关注
  • 前端

    前端技术一般分为前端设计和前端开发,前端设计可以理解为网站的视觉设计,前端开发则是网站的前台代码实现,包括 HTML、CSS 以及 JavaScript 等。

    246 引用 • 1338 回帖
  • 一些有用的避坑指南。

    69 引用 • 93 回帖
  • OpenStack

    OpenStack 是一个云操作系统,通过数据中心可控制大型的计算、存储、网络等资源池。所有的管理通过前端界面管理员就可以完成,同样也可以通过 Web 接口让最终用户部署资源。

    10 引用 • 5 关注
  • SendCloud

    SendCloud 由搜狐武汉研发中心孵化的项目,是致力于为开发者提供高质量的触发邮件服务的云端邮件发送平台,为开发者提供便利的 API 接口来调用服务,让邮件准确迅速到达用户收件箱并获得强大的追踪数据。

    2 引用 • 8 回帖 • 499 关注
  • CloudFoundry

    Cloud Foundry 是 VMware 推出的业界第一个开源 PaaS 云平台,它支持多种框架、语言、运行时环境、云平台及应用服务,使开发人员能够在几秒钟内进行应用程序的部署和扩展,无需担心任何基础架构的问题。

    5 引用 • 18 回帖 • 183 关注
  • 国际化

    i18n(其来源是英文单词 internationalization 的首末字符 i 和 n,18 为中间的字符数)是“国际化”的简称。对程序来说,国际化是指在不修改代码的情况下,能根据不同语言及地区显示相应的界面。

    8 引用 • 26 回帖 • 5 关注
  • Markdown

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

    170 引用 • 1529 回帖
  • Follow
    4 引用 • 12 回帖 • 11 关注
  • GitHub

    GitHub 于 2008 年上线,目前,除了 Git 代码仓库托管及基本的 Web 管理界面以外,还提供了订阅、讨论组、文本渲染、在线文件编辑器、协作图谱(报表)、代码片段分享(Gist)等功能。正因为这些功能所提供的便利,又经过长期的积累,GitHub 的用户活跃度很高,在开源世界里享有深远的声望,并形成了社交化编程文化(Social Coding)。

    210 引用 • 2040 回帖
  • RemNote
    2 引用 • 16 回帖 • 14 关注
  • Anytype
    3 引用 • 31 回帖 • 16 关注
  • 倾城之链
    23 引用 • 66 回帖 • 168 关注
  • 创业

    你比 99% 的人都优秀么?

    82 引用 • 1395 回帖
  • 链滴

    链滴是一个记录生活的地方。

    记录生活,连接点滴

    174 引用 • 3853 回帖
  • 阿里巴巴

    阿里巴巴网络技术有限公司(简称:阿里巴巴集团)是以曾担任英语教师的马云为首的 18 人,于 1999 年在中国杭州创立,他们相信互联网能够创造公平的竞争环境,让小企业通过创新与科技扩展业务,并在参与国内或全球市场竞争时处于更有利的位置。

    43 引用 • 221 回帖 • 60 关注
  • 996
    13 引用 • 200 回帖 • 8 关注
  • GraphQL

    GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。GraphQL 并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑。

    4 引用 • 3 回帖 • 13 关注
  • JetBrains

    JetBrains 是一家捷克的软件开发公司,该公司位于捷克的布拉格,并在俄国的圣彼得堡及美国麻州波士顿都设有办公室,该公司最为人所熟知的产品是 Java 编程语言开发撰写时所用的集成开发环境:IntelliJ IDEA

    18 引用 • 54 回帖 • 2 关注
  • Caddy

    Caddy 是一款默认自动启用 HTTPS 的 HTTP/2 Web 服务器。

    12 引用 • 54 回帖 • 177 关注
  • MongoDB

    MongoDB(来自于英文单词“Humongous”,中文含义为“庞大”)是一个基于分布式文件存储的数据库,由 C++ 语言编写。旨在为应用提供可扩展的高性能数据存储解决方案。MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似 JSON 的 BSON 格式,因此可以存储比较复杂的数据类型。

    91 引用 • 59 回帖 • 3 关注
  • 开源中国

    开源中国是目前中国最大的开源技术社区。传播开源的理念,推广开源项目,为 IT 开发者提供了一个发现、使用、并交流开源技术的平台。目前开源中国社区已收录超过两万款开源软件。

    7 引用 • 86 回帖
  • 设计模式

    设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

    200 引用 • 120 回帖
  • Eclipse

    Eclipse 是一个开放源代码的、基于 Java 的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。

    76 引用 • 258 回帖 • 629 关注
  • 微软

    微软是一家美国跨国科技公司,也是世界 PC 软件开发的先导,由比尔·盖茨与保罗·艾伦创办于 1975 年,公司总部设立在华盛顿州的雷德蒙德(Redmond,邻近西雅图)。以研发、制造、授权和提供广泛的电脑软件服务业务为主。

    8 引用 • 44 回帖
  • App

    App(应用程序,Application 的缩写)一般指手机软件。

    91 引用 • 384 回帖