如何正确地使用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>
本文作者:ou尼酱~~~
本文链接:https://www.cnblogs.com/--here--gold--you--want/p/14828370.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
分类:
android bug收集档
, recyclerview
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步