什么是 MergeAdapter ?
在最新的 recyclerview:1.2.0-alpha02[1] 中发布了一个关于 Adapter 的新特性 MergeAdapter 。咱们能够 “合并”Adapter,或者说给 Adapter “作加法”。android
听起来可能不是那么容易理解。咱们先来看下面的 RecyclerView 应该如何实现?git

源码地址见文末。程序员
实现起来其实很简单,利用现有的知识,大部分人都能想到用多类型的 itemView 。这里要区分三种类型,Teacher ,Student 和 Foot 。不一样的类型要对应不一样的布局文件,一样也对应不一样的业务逻辑。github
长久以来咱们一直都是这么作的。那么,你有没有想过这么作有什么不合理的地方吗?耦合度太高 。上面的示例中一个 Adapter 须要负责三套视图布局的呈现,若是是四套,五套,甚至更多呢?从 扩展性 上来讲,这个方案也不尽合理。web
既然如此,那就让每一个 Adapter 只负责一套视图布局。既下降了代码耦合度,又便于扩展。若是出现了新的布局类型,再来一个 Adapter 就好了。上面的示例中一共须要三个 Adapter,TeahcherAdapter
,StudentAdapter
,FootAdapter
。设计模式
TeahcherAdapter
负责展现列表最上面 Teacher 部分的视图。StudentAdapter
负责展现列表主体 Student 部分的视图。FootAdapter
负责展现列表底部加载状态的视图,包含加载中和无更多数据。微信
看起来很美好,各司其职,互不干扰。然而问题是,你的 RecyclerView 能够接受几个 Adapter ?编辑器
public void setAdapter(@Nullable Adapter adapter) {
// bail out if layout is frozen
setLayoutFrozen(false);
setAdapterInternal(adapter, false, true);
processDataSetCompletelyChanged(false);
requestLayout();
}
RecyclerView 显然是 “一夫一妻制” 。经过 setAdapter()
方法,咱们只能给 RecyclerView 设置一个 Adapter 。ide
在 recyclerview:1.2.0-alpha02 中,其实咱们仍然只能设置一个 Adapter ,可是这个 Adapter 能够是 MergeAdapter ,一个能够作加法的 Adapter 。函数
直接上代码。
private val teacherAdapter by lazy { TeacherAdapter() }
private val studentAdapter by lazy { StudentAdapter() }
private val stateAdapter by lazy { StateAdapter() }
val mergeAdater = MergeAdapter(teacherAdapter, studentAdapter, footAdapter)
recyclerView.adapter = mergeAdapter
使用方法就是如此的朴实无华,甚至有那么一点枯燥。MergeAdapter 构造函数中的参数顺序,就标识了列表中数据的显示顺序。
第一块布局是 Teacher 。在实际开发中,经常能够用做 Header View 。
class TeacherAdapter : ListAdapter<Teacher, TeacherViewHolder>(TeacherDiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TeacherViewHolder {
return TeacherViewHolder(
ItemTeacherBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: TeacherViewHolder, position: Int) {
holder.bind(getItem(position))
}
}
第二块布局是 Student 。也就是实际开发中的真正的列表数据。
class StudentAdapter : ListAdapter<Student, StudentViewHolder>(StudentDiffCallBack()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StudentViewHolder {
return StudentViewHolder(
ItemStudentBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: StudentViewHolder, position: Int) {
holder.bind(getItem(position))
}
}
最后一块布局是状态布局,也就是一般的 Footer 。包含正在加载,加载失败和无更多数据,三种状态。
class FootAdapter : ListAdapter<LoadState, StateViewHolder>(StateDiffCallBack()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StateViewHolder {
return StateViewHolder(
ItemStateBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: StateViewHolder, position: Int) {
holder.bind(getItem(position))
}
}
和日常的 Adapter 写法并没有二致。
有什么好处 ?
众所周知,RecyclerView 是一个设计极其精妙的类库,从源码里能够发现不少设计模式的身影。MergeAdapter 也不例外。
将一个 Adapter 负责多套布局,拆分为每一个 Adapter 只处理一个布局,大大下降代码耦合,这是 单一职责原则 。
面对新的需求,须要给 RecyclerView 增长一个新类型的 View。咱们须要作的仅仅只是添加新的 Adapter ,而无需修改以前的适配器代码。对扩展开放,对修改封闭,这是 开闭原则 。
有什么限制 ?
如上面的例子所示,MergeAdapter 的数据展现顺序,是按照构造函数中的参数顺序依次排列的,并且同类型的数据老是集中展现的。因此,对于不肯定性的,动态类型的复杂视图,MergeAdapter 是没法处理的。
另外说一点,称不上限制,应该说对 MergeAdapter 能力的指望。若是能支持多 LayoutManager 那就更好了。在多类型 RecyclerView 中,部分数据须要横向滑动展现,部分数据须要纵向滑动展现,这种状况已经比较常见了。
最后
MergeAdapter 的一些学习资源。
Android 开发团队的相关介绍:
https://medium.com/androiddevelopers/merge-adapters-sequentially-with-mergeadapter-294d2942127a
掘金译文:
https://juejin.im/post/5e86ffea51882573ba207a19
文中示例源码地址:
https://github.com/lulululbj/Sample
参考资料
recyclerview:1.2.0-alpha02: https://developer.android.com/jetpack/androidx/releases/recyclerview
---END---

本文分享自微信公众号 - 技术最TOP(Tech-Android)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。