Android ListAdapter 使用详解 (Java & Kotlin)

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这里不进行详细说明,前者只是为了视图的绑定,后者则是一个典型的观察者模式实现数据的更新。

  1. 这里直接给结论,之前Adapter在更新数据时,需要手动调用notifyDataSetChanged方法,实现以数据驱动的视图刷新,并且需要手动管理Adapter中的数据集合,而ListAdapter中使用了AsyncListDiffer,让数据管理更加轻松。

  2. 通过submitList来进行数据绑定

  3. 数据更新也通过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不需要

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容