如何实现融合多Adapter的Hybrid RecyclerView并按序展示列表项
多Adapter列表单RecyclerView整合实现方案
优先选用官方原生组件实现,无侵入、稳定性最高,完全适配现有开发限制,不需要修改已有的业务逻辑。
方案一:使用官方ConcatAdapter(推荐)
这个组件是AndroidX RecyclerView 1.2.0及以上版本提供的原生能力,专门解决多个Adapter顺序拼接展示的场景,完全不需要嵌套多个RecyclerView。
实现步骤如下:
- 保留之前编写的所有独立列表Adapter,包括其内部的ViewHolder逻辑、数据源请求逻辑、数据更新逻辑,不需要做任何修改
- 在Fragment中初始化唯一的RecyclerView实例,按需要的展示顺序,把所有待展示的Adapter实例传入
ConcatAdapter构造函数// 按展示顺序传入各Adapter实例,顺序和最终列表从上到下的展示顺序一致 val concatAdapter = ConcatAdapter( BannerAdapter(), CategoryNavAdapter(), SectionTitleAdapter("热门推荐"), HotGoodsAdapter(), SectionTitleAdapter("最新上架"), NewGoodsAdapter() ) // 给唯一的RecyclerView设置拼接后的Adapter即可 binding.recyclerView.adapter = concatAdapter - 各Adapter的数据加载完全独立:原本从不同数据源拉取数据的逻辑不需要调整,每个Adapter拿到自己的数据后,调用自身的
notifyDataSetChanged()或者差分更新方法即可,ConcatAdapter会自动完成全局位置映射,不会出现位置错位、viewtype冲突的问题 - 如果需要添加板块间隔、头布局、脚布局,只需要写对应简单逻辑的独立Adapter,插入到拼接顺序的对应位置即可,不需要修改现有业务Adapter的代码
这个方案天然绕开两个开发限制:
- 不需要在数据库存储viewtype字段,
ConcatAdapter内部会自动给每个子Adapter分配独立的viewtype取值区间,从底层避免不同Adapter的viewtype冲突,完全不需要手动维护多布局类型映射- 不需要合并多个数据源,每个子Adapter只和自己的数据源绑定,数据请求、更新完全隔离,适配多数据源拉取的场景
方案二:自定义代理Adapter(适配低版本RecyclerView)
如果项目依赖的RecyclerView版本低于1.2.0,无法使用ConcatAdapter,可以自己实现轻量的代理拼接Adapter,核心逻辑和官方实现一致:
- 自定义一个
ProxyAdapter,内部维护一个List<Adapter<ViewHolder>>类型的列表,按展示顺序存储所有子Adapter - 重写
getItemCount()方法,遍历所有子Adapter累加itemCount,作为全局列表的总条目数 - 实现位置换算的工具方法:传入全局position,遍历子Adapter列表,找到当前position对应的子Adapter实例,以及该position在子Adapter内部的相对位置
- 重写
getItemViewType()方法,给每个子Adapter的viewtype加上固定偏移量(比如每个子Adapter预留1000个viewtype的区间),避免不同子Adapter的viewtype取值重复 - 重写
onCreateViewHolder、onBindViewHolder方法,通过位置换算找到对应的子Adapter,把创建、绑定逻辑转发给对应子Adapter处理,注意传入子Adapter内部的相对位置 - 给每个子Adapter注册数据变更观察者,当子Adapter调用数据更新方法时,计算对应全局位置的偏移量,调用
ProxyAdapter对应的notify方法刷新列表即可
避坑提示
- 不要手动把不同数据源的数据强转成Object类型拼成同一个大列表,再自己实现多ViewHolder适配:这种方案需要重构所有现有Adapter的逻辑,还要手动处理类型判断、位置换算,后续新增、调整板块顺序的维护成本极高
- 列表点击事件、子条目动画、吸顶效果等能力,都可以直接在对应子Adapter中实现,或者配合
ItemDecoration、ItemAnimator实现,和单独使用子Adapter时的逻辑没有差异
内容的提问来源于stack exchange,提问作者Fortray
相关产品推荐
相关产品推荐

