1. 简介
这次想要介绍的是由谷歌推出的MergeAdapter
。听名字就应该知道它是和RecyclerView
相关的组件。
该组件是在androidx.recyclerview:recyclerview:1.2.0-alpha02
中推出,它的主要中作用是把多个Adapter
集中在一个Adapter
中,然后在RecyclerView
中显示。
所以如果想实现RecyclerView
中显示不同的ViewType
就需要利用RecyclerView
的getItemViewType
,或者使用类似于Groupie
(关于Groupie的教程)的外部库。
但是有了MergeAdapter
, 我们可以直接使用它就可以实现上述的需求,非常的方便,而且足够优雅。
废话不多说,先介绍用法,然后再讨论它的好与不足。
2. 使用方法
2.1 引入库
在build.gradle
中加入RecyclerView
的库。
androidx.recyclerview:recyclerview:1.2.0-alpha02
复制代码
2.2 创建Adapter的Layout
这里根据自己的需求创建layout,需要多少ViewType
就创建相应的layout就可以了。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp">
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/black"
android:textSize="20sp"
android:layout_marginStart="20dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:text="hello" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
复制代码
2.3 创建Adapter
这里也是根据自己的需求创建Adapter就可以了。和正常的用法一样。
class FirstAdapter(private val data: List<String>) :
ListAdapter<String, FirstAdapter.ViewHolder>(DiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from((parent.context))
val binding: ItemFirstBinding =
DataBindingUtil.inflate(inflater, R.layout.item_first, parent, false)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.binding.textView1.text = data[position]
}
override fun getItemCount(): Int {
return data.size
}
class DiffCallback : DiffUtil.ItemCallback<String>() {
override fun areContentsTheSame(oldItem: String, newItem: String): Boolean {
return oldItem == newItem
}
override fun areItemsTheSame(oldItem: String, newItem: String): Boolean {
return oldItem === newItem
}
}
class ViewHolder(var binding: ItemFirstBinding) : RecyclerView.ViewHolder(binding.root)
复制代码
2.4 创建MergeAdapter
我们在MainActivity中创建MergeAdapter
然后传RecyclerView
。
val firstAdapter = FirstAdapter(data)
val secondAdapter = SecondAdapter(data)
val thirdAdapter = ThirdAdapter(data)
// 创建MergeAdapter
// 需要通过listOf把多个adapter传给MergeAdapter
mergeAdapter = MergeAdapter(listOf(firstAdapter,secondAdapter,thirdAdapter))
binding.recyclerView.adapter = mergeAdapter
复制代码
3. 关于MergeAdapter
3.1 移除adapter
可以对已经存在的adapter进行移除。
mergeAdapter.removeAdapter(firstAdapter)
复制代码
3.2 添加adapter
可以在MergeAdapter
传给RecyclerView
以后,还以可以添加adapter。
mergeAdapter.addAdapter(firstAdapter)
复制代码
3.3 获取当前的adapter数组
可以获取当前已经传给RecyclerView
的adapter数组。
val adapters = mergeAdapter.adapters
复制代码
3.4 adapter的复用
默认的情况是每个adapter
都会维护自己的ViewHolder pool
,且adapter
之间不能复用。如果我们想要复用则需要设置MergeAdapter.Config
。
val configBuilder = MergeAdapter.Config.Builder()
configBuilder.setIsolateViewTypes(false)
复制代码
然后在创建MergeAdapter
的时候,把Config
传进去。
val mergeAdapter = MergeAdapter(configBuilder.build(),listOf(firstAdapter,secondAdapter,thirdAdapter))
复制代码
3.5 数据更新的通知
需要有新数据更新时调用相应的adapter
, 然后用相应的adapter
的notifyDatasetChanged
。调用adapter
的notifyDatasetChanged
,最后MergeAdapter
的notifyDatasetChanged
也会被调用。
thirdAdapter.submitList(addData())
thirdAdapter.notifyDataSetChanged()
复制代码
4. 不足之处
有点自然不必多说,但是MergeAdapter
有一个显而易见的不足之处就是ViewType
不能混合使用,使其应用范围受到了很大的限制。但是如果没有这样的需求则还是优先使用MergeAdapter
吧!
5. GitHub
GitHub: github.com/HyejeanMOON…
关于Jetpack的Paging教程: juejin.im/post/5e75db…
Groupie的教程: juejin.im/post/5e9059…