ListAdapter
第一次发现这个适配器要从google的经典demo sunflower说起了。
如何让Adapter简洁且优雅(其实很多人都在致力于给Adapter减负,作为一个适配器,它要调节View和数据的关联,导致它需要维护一整套视图的同时又要维护一系列的数据),经典的像是BRVAH。他其实已经做的很好了,里面包含了很多常用的场景,具体的话我以后再介绍。
回到ListAdapter,直接看如何使用不bb
kotlin
Fragment / Activity
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding = FragmentPlantListBinding.inflate(inflater, container, false)
context ?: return binding.root
val adapter = PlantAdapter() // 1.为什么这里把adapter作为方法中的变量?
binding.plantList.adapter = adapter // 2.数据怎么绑定上的?
subscribeUi(adapter)// 3.怎么更新数据?
return binding.root
}
private fun subscribeUi(adapter: PlantAdapter) {
viewModel.plants.observe(viewLifecycleOwner) { plants ->
adapter.submitList(plants)
}
}
上面这段kotlin代码第一次用ListAdapter的人肯定会有这样的疑问:
除去里面使用databinding和LiveData这里不进行详细说明,前者只是为了视图的绑定,后者则是一个典型的观察者模式实现数据的更新。
这里直接给结论,之前Adapter在更新数据时,需要手动调用notifyDataSetChanged方法,实现以数据驱动的视图刷新,并且需要手动管理Adapter中的数据集合,而ListAdapter中使用了AsyncListDiffer,让数据管理更加轻松。
通过submitList来进行数据绑定
-
数据更新也通过submitList(这里你肯定会问,每次都submitList是不是会影响效率)
AsyncListDiffer 的作用
直接上Adapter代码
class PlantAdapter : ListAdapter<Plant, RecyclerView.ViewHolder>(PlantDiffCallback()) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { // 初始化ViewHolder return PlantViewHolder( ListItemPlantBinding.inflate( LayoutInflater.from(parent.context), parent, false ) ) } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { val plant = getItem(position) // 直接通过getItem获取数据 (holder as PlantViewHolder).bind(plant)// 绑定视图和数据 } class PlantViewHolder( private val binding: ListItemPlantBinding ) : RecyclerView.ViewHolder(binding.root) { } fun bind(item: Plant) { // 绑定方法 binding.apply { plant = item executePendingBindings() // 注意: 这个方法不调用可能导致item闪烁 } } } } private class PlantDiffCallback : DiffUtil.ItemCallback<Plant>() { override fun areItemsTheSame(oldItem: Plant, newItem: Plant): Boolean { return oldItem.plantId == newItem.plantId // 通过id判断是否是相同的item } override fun areContentsTheSame(oldItem: Plant, newItem: Plant): Boolean { return oldItem == newItem // 通过对象判断是否是相同的Content } }
这里出现了PlantDiffCallback,这又是做什么的呢,我们再回到submitList源码中
@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
T oldItem = oldList.get(oldItemPosition);
T newItem = newList.get(newItemPosition);
if (oldItem != null && newItem != null) {
return mConfig.getDiffCallback().areItemsTheSame(oldItem, newItem);
}
// If both items are null we consider them the same.
return oldItem == null && newItem == null;
}
@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
T oldItem = oldList.get(oldItemPosition);
T newItem = newList.get(newItemPosition);
if (oldItem != null && newItem != null) {
return mConfig.getDiffCallback().areContentsTheSame(oldItem, newItem);
}
if (oldItem == null && newItem == null) {
return true;
}
// There is an implementation bug if we reach this point. Per the docs, this
// method should only be invoked when areItemsTheSame returns true. That
// only occurs when both items are non-null or both are null and both of
// those cases are handled above.
throw new AssertionError();
}
源码就是通过之前的回调,去判断哪些item需要替换,哪些item不需要