如何正确地使用RecyclerView.ListAdapter
默认是在一个fragment中实现RecyclerView.
private inner class CrimeAdapter() :
ListAdapter<Crime, CrimeHolder>(mDiffCallback) { override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): CrimeHolder {//这个parent就是RecyclerView;在这个方法中绑定子项视图
val view = layoutInflater.inflate(
R.layout.fragment_crime_list_item,
parent,
false
)//负责创建要显示的视图,并封装到ViewHolder里
return CrimeHolder(view)
} override fun onBindViewHolder(
holder: CrimeHolder,
position: Int
) {//负责将数据集里指定位置的crime数据发送给指定的ViewHolder
val crime = currentList[position]
holder.bind(crime)//把viewholder和adapter的处理逻辑分开,只需调用viewholder的方法
} }
- 构造函数里也不需要传一个list了,在onBindViewHolder里原来是list[position],现在可以用currentList。这个字段是ListAdapter里面的。之前我的一个bug就是这个B弄的。
- 继承自ListAdapter, <模型类, 自定义holder>, 参数需要一个DiffUtil.ItemCallback<Crime>()实例,可以在这个fragment里以伴随类的方式定义。
companion object {
val mDiffCallback = object : DiffUtil.ItemCallback<Crime>() {//作为ListAdapter的参数
override fun areItemsTheSame(oldItem: Crime, newItem: Crime): Boolean {
return oldItem.id == newItem.id
} override fun areContentsTheSame(oldItem: Crime, newItem: Crime): Boolean {
return oldItem.title == newItem.title
}
}必须实现这两个方法,第一个方法检测item是否相同,第二个检测item内容是否相同。这两个方法都很重要。第二个方法如果比较的item的属性不对,更新会有延迟!!比如说比较的是id,那我更改了title,我回到列表界面时,他判断我的id没变,所以内容没变,结果他不给我更新我操他妈的。上面那个写法也是不完整的,只比较了title,那我更改了其他信息,回到主界面也是不会立即更新的,会有一个延迟。
- 重头戏!!!那如何提交recycleview列表的更新呢?首先在fragment字段中定义一个adapter, 然后让recyclerview的adapter字段指向这个adapter, 然后因为传进去的列表是livedata,所以我们用observe检测数据变化,一有变化就用ListAdapter里的方法——submitList来提交,到这里就明白了,我们取消了原来以参数的方式传列表进去,改为submitList.(更删改查都用它,反正有变化就用它)
private var mAdapter: CrimeAdapter = CrimeAdapter()
override fun onCreateView(//onCreateview方法里不用做什么和本文相关的事,看下面
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentCrimeListBinding.inflate(inflater, container, false)
binding.crimeRecyclerview.layoutManager =
LinearLayoutManager(context)//把加载的recyclerview视图的布局设为线性布局
return binding.root
}override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) binding.crimeRecyclerview.adapter = mAdapter//
crimeListViewModel.crimeListLiveData.observe(
viewLifecycleOwner,
{ crimes ->
crimes?.let {
mAdapter.submitList(crimes)//有更新就提交给adapter
}
}
)
} - 注意!!传给submitList的列表不能是同一个列表引用,如果是同一个列表引用的话要拷贝一份,
新拿到的数据根本没有更新到列表中来。问题可能出在 submitList() 方法上: public void submitList(@Nullable List<T> list) {
mDiffer.submitList(list);
} 最终调用的是 AsyncListDiffer 类中的 submitList() 方法: 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;
}
final List<T> oldList = mList;
// 省略一些代码。
} 第一次我们调用 submitList() 方法时,把成员变量集合 list 传递过来,那么 newList 参数就不为 null,在第 25 行,会进入 if 语句,把 newList 赋值给 mList,也就是把 list 赋值给 mList。 第二次我们调用submitList() 方法时,仍是把成员变量集合 list 传递过来,这时 mList 就是指向的 list,所以第 5 行的 if (newList == mList) 成立,进而直接 return 掉 submitList() 方法。新的数据并未更新到列表中。因为livedata的observe传给我们的不是同一个列表引用,所以可以直接放进去submitList.
最后加上一份官方的示例代码
A complete usage pattern with Room would look like this:
* <pre>
* {@literal @}Dao
* interface UserDao {
* {@literal @}Query("SELECT * FROM user ORDER BY lastName ASC")
* public abstract LiveData<List<User>> usersByLastName();
* }
*
* class MyViewModel extends ViewModel {
* public final LiveData<List<User>> usersList;
* public MyViewModel(UserDao userDao) {
* usersList = userDao.usersByLastName();
* }
* }
*
* class MyActivity extends AppCompatActivity {
* {@literal @}Override
* public void onCreate(Bundle savedState) {
* super.onCreate(savedState);
* MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class);
* RecyclerView recyclerView = findViewById(R.id.user_list);
* UserAdapter<User> adapter = new UserAdapter();
* viewModel.usersList.observe(this, list -> adapter.submitList(list));/////////直接用行了
* recyclerView.setAdapter(adapter);
* }
* }
*
* class UserAdapter extends ListAdapter<User, UserViewHolder> {
* public UserAdapter() {
* super(User.DIFF_CALLBACK);
* }
* {@literal @}Override
* public void onBindViewHolder(UserViewHolder holder, int position) {
* holder.bindTo(getItem(position));
* }
* public static final DiffUtil.ItemCallback<User> DIFF_CALLBACK =
* new DiffUtil.ItemCallback<User>() {
* {@literal @}Override
* public boolean areItemsTheSame(
* {@literal @}NonNull User oldUser, {@literal @}NonNull User newUser) {
* // User properties may have changed if reloaded from the DB, but ID is fixed
* return oldUser.getId() == newUser.getId();
* }
* {@literal @}Override
* public boolean areContentsTheSame(
* {@literal @}NonNull User oldUser, {@literal @}NonNull User newUser) {
* // NOTE: if you use equals, your object must properly override Object#equals()
* // Incorrectly returning false here will result in too many animations.
* return oldUser.equals(newUser);
* }
* }
* }</pre>
如何正确地使用RecyclerView.ListAdapter的更多相关文章
- WanJetpack项目:用Jetpack实现玩Android,追求最官方的实现方式
项目简介 玩Android demo.用Jetpack MVVM开发架构.单Activity多Fragment项目设计,项目结构清晰,代码简洁优雅,追求最官方的实现方式.用到以下知识点: LiveDa ...
- Android RecyclerView使用ListAdapter高效刷新数据
原文:Android RecyclerView使用ListAdapter高效刷新数据 - Stars-One的杂货小窝 我们都知道,当RecyclerView数据源更新后,还需要通过adapter调用 ...
- RecyclerView添加Header的正确方式
原文链接:http://blog.csdn.net/qibin0506/article/details/49716795 看了一下博客目录,已经有好几篇博客是关于RecyclerView的,不过对于这 ...
- <Android 基础(三十五)> RecyclerView多类型Item的正确实现姿势
简介 RecyclerView是我们开发过程中经常使用到的一个元素,原生的RecyclerView.Adapter基本上可以满足一般的需求,关于RecyclerView的基础介绍请移步: Recycl ...
- 【Android】【踩坑日记】RecyclerView获取子View的正确姿势
开发过程中发现RecyclerView.getChildAt(position)为空的情况,但是明明这个position却没有越界. 解决办法:用recycler.getLayoutManager() ...
- Android 高级UI设计笔记07:RecyclerView 的详解
1. 使用RecyclerView 在 Android 应用程序中列表是一个非常重要的控件,适用场合非常多,如新闻列表.应用列表.消息列表等等,但是从Android 一出生到现在并没有非常 ...
- Android RecyclerView体验(一)- 简介
在网上关于RecyclerView的基本使用方式已经有了比较详细介绍,而且其设计结构也类似于ListView,所以本文将不重点介绍如何使用,在文末的引用中都可以相关内容.这里主要是介绍Recycler ...
- RecyclerView使用大全
RecylerView介绍 RecylerView是support-v7包中的新组件,是一个强大的滑动组件,与经典的ListView相比,同样拥有item回收复用的功能,这一点从它的名字recyler ...
- 带你实现开发者头条APP(五)--RecyclerView下拉刷新上拉加载
title: 带你实现开发者头条APP(五)--RecyclerView下拉刷新上拉加载 tags: -RecyclerView,下拉刷新,上拉加载更多 grammar_cjkRuby: true - ...
随机推荐
- Day14_78_可变长参数
可变长参数 可变长参数只能在形参列表的最后一个,且只能出现一次. 代码实例 import java.util.Date; public class 可变长参数 { public static void ...
- 图解高性能网络架构:Reactor 和 Proactor
小林,来了. 这次就来图解 Reactor 和 Proactor 这两个高性能网络模式. 别小看这两个东西,特别是 Reactor 模式,市面上常见的开源软件很多都采用了这个方案,比如 Redis.N ...
- 常用head标签
最小推荐 <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content= ...
- 【CompletableFuture】CompletableFuture测试runAsync()方法调用
问题 CompletableFuture.runAsync() 返回 CompletableFuture<Void>对象,调用CompletableFuture.allOf(f1,f2). ...
- Windows系统之间文件互传
1)利用Windows自带的文件共享服务 本次试验以Win7为服务器端,win10为客户端 1.确保Win7服务端开启对应的服务及开放相应的端口号 进入命令行界面,输入netstat -an,查看44 ...
- Android Hook学习之ptrace函数的使用
Synopsis #include <sys/ptrace.h> long ptrace(enum __ptrace_request request, pid_t pid, void *a ...
- 从苏宁电器到卡巴斯基第09篇:我在苏宁电器当营业员 I
毕竟应聘的是营业员,门槛还是很低的 我应聘苏宁的时候已经到了2009年的8月初,记得当时苏宁电器的长春总部还在吉林大路与东盛大街交汇处的亚泰广场,我当时的面试就是在那里. 我记得很清楚,那天等待面试的 ...
- POJ 1679 判断最小树是否唯一
题意: 给你一个图,问你最小树是否唯一,唯一则输出最小数的权值,不唯一输出Not Unique! 思路: 题目问的是最小树是否唯一,其实也就是在问次小树是否等于最小树,如果等于则 ...
- HTTPS协议工作原理(SSL数字证书)
目录 HTTPS SSL协议的工作过程 SSL数字证书的查看 HTTPS 我们都知道HTTP协议是明文传输的,并且不能验证对方的身份,而且不能保证数据的完整性.而当我们在网络上进行购物电子交易时,电子 ...
- Python脚本破解图形验证码(tesserocr和pytesseract)
在学习之前,我们先了解OCR.tesseract.tesserocr.pytesseract和opencv这几个跟图片处理有关的库. OCR(Optical Character Recognition ...