目录:

  ListAdapter 简介及优势

  开始使用

  DiffUtil 

  areContentsTheSame 不能更新条目的原因

前言:

  listAdapter?? 是的你没有听错...  算了不解释了,都1202年了;  它是    androidx.recyclerview.widget  包下为RecycleView服务的类;

ListAdapter 的优势:

  1. 刷新列表只需要 submitList 这一个方法;  而避免原Adapter 增删改 的各种 notifyItem.. 操作;

  2. AsyncListDiffer 异步计算新旧数据差异, 并通知 Adapter 刷新数据

  3. 真正的数据驱动, 无论增删改查 我们只需要关心并操作数据集.

使用:

1.新建Adapter 继承  ListAdapter;  泛型提供 数据集实体类 和 自定义的 ViewHolder;  构造函数提供了 自定义的 DiffCallback()

DiffCallback 继承自 DiffUtil.ItemCallback  稍安勿躁后面会讲到;  跳转

class TestAdapter : ListAdapter<DynamicTwo, NewViewHolder>(DiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NewViewHolder {
TODO("Not yet implemented")
} override fun onBindViewHolder(holder: NewViewHolder, position: Int) {
TODO("Not yet implemented")
}
}

2. onCreateViewHolder 的代码比较简单, MVVM模式, 直接返回 用 ViewDataBinding 构造的 ViewHolder; 只有一个可变参数, 即布局资源文件ID;

onBindViewHolder 的代码更简单,  拿到数据实体 并交给 ViewHolder 处理即可;

   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NewViewHolder {
return NewViewHolder(
DataBindingUtil.inflate(
LayoutInflater.from(parent.context),
R.layout.item_dynamic_img, parent, false
)
)
} override fun onBindViewHolder(holder: NewViewHolder, position: Int) {
holder.bind(getItem(position))
}

3. ViewHolder 的代码:  

open class NewViewHolder(val binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root){
fun bind(item: BaseItem?) {
binding.setVariable(BR.item, item)
binding.executePendingBindings()
}
}

4. DiffCallback 代码:

class DiffCallback : DiffUtil.ItemCallback<DynamicTwo>() {
override fun areItemsTheSame(oldItem: DynamicTwo, newItem: DynamicTwo): Boolean {
return oldItem === newItem
}

override fun areContentsTheSame(oldItem: DynamicTwo, newItem: DynamicTwo): Boolean {
return !oldItem.hasChanged
}
}

5. 操作数据:   Adapter 新建跟以往没有区别.

mAdapter = TestAdapter()
mDataBind.rvRecycle.let {
it.layoutManager = LinearLayoutManager(mActivity)
it.adapter = mAdapter
}

5.1 增删操作比较简单, 只需要更改数据集, 并 submitList 即可

注意:  这里需要用新数据集对象操作!!! 切记

fun addData(){
val data = mutableListOf<DynamicTwo>() //currentList 不需要判空, 它有默认的空集合
data.addAll(mAdapter.currentList)
repeat(10){
data.add(DynamicTwo())
}
mAdapter.submitList(data)
} fun deleteItem(position: Int){
val data = mutableListOf<DynamicTwo>()
data.addAll(mAdapter.currentList)
data.removeAt(position)
mAdapter.submitList(data)
} fun updateItem(position: Int){
//TODO 暂放
}

为什么这里必须要用新集合对象操作?  我们来看一下 submitList 的源码

  public void submitList(@Nullable List<T> list) {
mDiffer.submitList(list);
}   public void submitList(@Nullable final List<T> newList,
@Nullable final Runnable commitCallback) {
// incrementing generation means any currently-running diffs are discarded when they finish
final int runGeneration = ++mMaxScheduledGeneration; if (newList == mList) {
// nothing to do (Note - still had to inc generation, since may have ongoing work)
if (commitCallback != null) {
commitCallback.run();
}
return;
} final List<T> previousList = mReadOnlyList; // fast simple remove all
if (newList == null) {
//noinspection ConstantConditions
int countRemoved = mList.size();
mList = null;
mReadOnlyList = Collections.emptyList();
// notify last, after list is updated
mUpdateCallback.onRemoved(0, countRemoved);
onCurrentListChanged(previousList, commitCallback);
return;
} // fast simple first insert
if (mList == null) {
mList = newList;
mReadOnlyList = Collections.unmodifiableList(newList);
// notify last, after list is updated
mUpdateCallback.onInserted(0, newList.size());
onCurrentListChanged(previousList, commitCallback);
return;
}
    .....
  }
mList 为旧集合对象; 红字部分(JAVA 代码) 可以看出, 当新旧数据为同一对象时return 就不再往下执行了. 
ListAdapter 认为新旧数组为同一对象时, nothing to do.
我们可以认为这是 ListAdapter 的一个特性. 也许它只是提醒我们 不要做无效刷新操作;
当然我们也可以重写
submitList 方法, 然后自动新建数据集.

5.2 DiffUtil
讲更新操作前, 需要先讲 DiffUtil

引用官方话术:
DiffUtil 是 ListAdapter 能够高效改变元素的奥秘所在。DiffUtil 会比较新旧列表中增加、移动、删除了哪些元素,然后输出更新操作的列表将原列表中的元素高效地转换为新的元素。

简单理解:
ListAdpater 就是通过 DiffUtil 计算前后集合的差异, 得出增删改的结果. 通知Adapter做出对应操作;
5.2.1 areItemsTheSame(): 比较两个对象是否是同一个 Item;
常见的比较方式: 可自行根据情况或个人习惯选用
  1.比较内存地址: java(==) kotlin(===)
  2.比较两个对象的 Id; 一般对象在库表中都有主键 ID 参数; 相同的情况下,必定为同一条记录;
  3.equals: java(obj.
equals(other)) kotlin(==)
5.2.2 areContentsTheSame(): 在已经确定同一 Item 的情况下, 再确定是否有内容更新;
网上给出的比较方式几乎全是
equals; 但 equals 运用不当根本刷新不了 Item;
  1.当 areItemsTheSame() 选用 比较内存地址 的方式时, areContentsTheSame() 不能用equals方式;
  2.当某个具体的 Item 更新时, 必定会替换为一个新实体对象时. 可以用 equals 方式;
    也就是说,当我给某个动态条目点赞时, 必须要 copy 一个新的动态对象, 给新对象设置点赞状态为 true; 然后再用新对象替换掉数据集中的旧对象.
equals 刷新才能奏效;
  3.当更新某个Item, 不确定是否为新Item对象实体时, 不能用
equals 方式;

  总结: 同一个内存地址的对象
equals 有个鸡儿用? 有个鸡儿用??

  状态标记方式:
  实体对象中增加: hasChanged: Boolean 字段; 当对象内容变化时,设置 hasChanged 为true; ViewHolder.bind()时,置为false;
 
给最终的 ViewHolder  DiffCallback
class DiffCallback : DiffUtil.ItemCallback<DynamicTwo>() {
override fun areItemsTheSame(oldItem: DynamicTwo, newItem: DynamicTwo): Boolean {
return oldItem === newItem
} override fun areContentsTheSame(oldItem: DynamicTwo, newItem: DynamicTwo): Boolean {
return !oldItem.hasChanged
}
} open class NewViewHolder(val binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root){
fun bind(item: BaseItem?, index: Int) {
item?.hasChanged = false
binding.setVariable(BR.item, item)
binding.executePendingBindings()
}
}

5.3 更新操作:

fun updateItem(position: Int){
val data = mutableListOf<DynamicTwo>()
data.addAll(mAdapter.currentList)
data[position].let {
it.title = "变变变 我是百变小魔女"
it.hasChanged = true
}
mAdapter.submitList(data)
}

 最后:

  ListAdapter 可完美的 由数据驱动 UI,  增删改可以放到 ViewModel中, 请求成功后直接操作数据集合 更新列表即可.  

回到顶部
 

 

孟老板 BaseAdapter封装(五) ListAdapter的更多相关文章

  1. 孟老板 BaseAdapter封装 (一) 简单封装

    BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...

  2. 孟老板 BaseAdapter封装 (二) Healer,footer

    BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...

  3. 孟老板 BaseAdapter封装 (三) 空数据占位图

    BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...

  4. 孟老板 BaseAdapter封装(四) PageHelper

    BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...

  5. 孟老板 ListAdapter封装, 告别Adapter代码 (上)

    BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...

  6. 孟老板 ListAdapter封装, 告别Adapter代码 (三)

    BaseAdapter系列 ListAdapter封装, 告别Adapter代码 (一) ListAdapter封装, 告别Adapter代码 (二) ListAdapter封装, 告别Adapter ...

  7. 孟老板 ListAdapter封装, 告别Adapter代码 (四)

    BaseAdapter系列 ListAdapter封装, 告别Adapter代码 (一) ListAdapter封装, 告别Adapter代码 (二) ListAdapter封装, 告别Adapter ...

  8. 孟老板 Paging3 (二) 结合Room

    BaseAdapter系列 ListAdapter系列 Paging3 (一) 入门 Paging3 (二) 结合 Room Paging3 (二)  结合Room Paging 数据源不开放, 无法 ...

  9. 孟老板 Paging3 (一) 入门

    BaseAdapter系列 ListAdapter系列 Paging3 (一) 入门 Paging3 (二) 结合 Room Paging3 (一)  入门 前言: 官方分页工具,  确实香.   但 ...

随机推荐

  1. Linux中数据库的安装和配置(MySQL与Maria DB)

    目录 MySQL和Maria DB的介绍 MySQL和Maria DB的安装 yum源安装MySQL(Centos6.5+Mysql5.1) 源码包安装MySQL yum源安装Maria DB 源码包 ...

  2. 异步访问技术Ajax(XMLHttpRequest)

    目录 AJAX XMLHttpRequest Ajax向服务器发送请求 Ajax接收服务器响应 AJAX - onreadystatechange 事件 使用 Callback 函数 一次Ajax请求 ...

  3. java线程池实践

    线程池大家都很熟悉,无论是平时的业务开发还是框架中间件都会用到,大部分都是基于JDK线程池ThreadPoolExecutor做的封装, 都会牵涉到这几个核心参数的设置:核心线程数,等待(任务)队列, ...

  4. JDBC相关配置和操作

    获取数据库连接的几种方式 ps.数据库URL : String url = "jdbc:mysql://localhost:3306/dailytext?useSSL=false&s ...

  5. MarkDown写ppt

    首先给你的VSCode安装插件 MarkDown语法 例子 --- marp: true paginate: true theme: default class: - lead - invert si ...

  6. 【BUAA_2020_软工】个人作业

    个人项目作业博客 1. 在文章开头给出教学班级和可克隆的 Github 项目地址(例子如下).(1') 项目 内容 北航2020软工 班级博客 作业要求 具体要求 项目GitHub地址 个人项目 教学 ...

  7. Scrum Meeting 2

    Basic Info where:三号教学楼 when:2020/4/25 target: 简要汇报一下已完成任务,下一步计划与遇到的问题 Progress Team Member Position ...

  8. mysql 索引十连问| 剑指 offer - mysql

    以下是结合网上及此前面试时遇到的一些关于mysql索引的面试题. 若对mysql索引不太了解可先翻阅相关文章 大白话 mysql 之深入浅出索引原理 - 上 大白话 mysql 之深入浅出索引原理 - ...

  9. [Java] 数据分析 -- 回归分析

    线性回归 需求:从文件读取数据对,计算回归函数及系数 实现1:commons.math的SimpleRegression,定义函数getData从文件读取数据返回SimpleRegression类 1 ...

  10. [java] XML DTD XSD

    XML是用来干什么的 https://bbs.csdn.net/topics/120762 https://blog.csdn.net/Rain722/article/details/52925828 ...