孟老板 BaseAdapter封装(五) ListAdapter
- BaseAdapter封装(一) 简单封装
- BaseAdapter封装(二) Header,footer
- BaseAdapter封装(三) 空数据占位图
- BaseAdapter封装(四) PageHelper
- BaseAdapter封装(五) ListAdapter
- BaseAdapter封装(六) Healer,footer for List
- BaseAdapter封装(七) ConcatAdapter 改建头尾
- BaseAdapter封装(八) Paging 分页
目录:
前言:
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的更多相关文章
- 孟老板 BaseAdapter封装 (一) 简单封装
BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...
- 孟老板 BaseAdapter封装 (二) Healer,footer
BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...
- 孟老板 BaseAdapter封装 (三) 空数据占位图
BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...
- 孟老板 BaseAdapter封装(四) PageHelper
BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...
- 孟老板 ListAdapter封装, 告别Adapter代码 (上)
BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...
- 孟老板 ListAdapter封装, 告别Adapter代码 (三)
BaseAdapter系列 ListAdapter封装, 告别Adapter代码 (一) ListAdapter封装, 告别Adapter代码 (二) ListAdapter封装, 告别Adapter ...
- 孟老板 ListAdapter封装, 告别Adapter代码 (四)
BaseAdapter系列 ListAdapter封装, 告别Adapter代码 (一) ListAdapter封装, 告别Adapter代码 (二) ListAdapter封装, 告别Adapter ...
- 孟老板 Paging3 (二) 结合Room
BaseAdapter系列 ListAdapter系列 Paging3 (一) 入门 Paging3 (二) 结合 Room Paging3 (二) 结合Room Paging 数据源不开放, 无法 ...
- 孟老板 Paging3 (一) 入门
BaseAdapter系列 ListAdapter系列 Paging3 (一) 入门 Paging3 (二) 结合 Room Paging3 (一) 入门 前言: 官方分页工具, 确实香. 但 ...
随机推荐
- Linux中数据库的安装和配置(MySQL与Maria DB)
目录 MySQL和Maria DB的介绍 MySQL和Maria DB的安装 yum源安装MySQL(Centos6.5+Mysql5.1) 源码包安装MySQL yum源安装Maria DB 源码包 ...
- 异步访问技术Ajax(XMLHttpRequest)
目录 AJAX XMLHttpRequest Ajax向服务器发送请求 Ajax接收服务器响应 AJAX - onreadystatechange 事件 使用 Callback 函数 一次Ajax请求 ...
- java线程池实践
线程池大家都很熟悉,无论是平时的业务开发还是框架中间件都会用到,大部分都是基于JDK线程池ThreadPoolExecutor做的封装, 都会牵涉到这几个核心参数的设置:核心线程数,等待(任务)队列, ...
- JDBC相关配置和操作
获取数据库连接的几种方式 ps.数据库URL : String url = "jdbc:mysql://localhost:3306/dailytext?useSSL=false&s ...
- MarkDown写ppt
首先给你的VSCode安装插件 MarkDown语法 例子 --- marp: true paginate: true theme: default class: - lead - invert si ...
- 【BUAA_2020_软工】个人作业
个人项目作业博客 1. 在文章开头给出教学班级和可克隆的 Github 项目地址(例子如下).(1') 项目 内容 北航2020软工 班级博客 作业要求 具体要求 项目GitHub地址 个人项目 教学 ...
- Scrum Meeting 2
Basic Info where:三号教学楼 when:2020/4/25 target: 简要汇报一下已完成任务,下一步计划与遇到的问题 Progress Team Member Position ...
- mysql 索引十连问| 剑指 offer - mysql
以下是结合网上及此前面试时遇到的一些关于mysql索引的面试题. 若对mysql索引不太了解可先翻阅相关文章 大白话 mysql 之深入浅出索引原理 - 上 大白话 mysql 之深入浅出索引原理 - ...
- [Java] 数据分析 -- 回归分析
线性回归 需求:从文件读取数据对,计算回归函数及系数 实现1:commons.math的SimpleRegression,定义函数getData从文件读取数据返回SimpleRegression类 1 ...
- [java] XML DTD XSD
XML是用来干什么的 https://bbs.csdn.net/topics/120762 https://blog.csdn.net/Rain722/article/details/52925828 ...