Paging2之PagedListAdapter 个人小结
来源:5-8 paging框架工作原理2【难点】

慕慕6500093
2022-11-18
三、PagedListAdapter
RecyclerView.Adapter base class for presenting paged data from PagedLists in a RecyclerView.This class is a convenience wrapper around AsyncPagedListDiffer that implements common default behavior for item counting, and listening to PagedList update callbacks.
它是用于在RecyclerView中显示PagedList中的分页数据的适配器基类,同时持有AsyncPagedListDiffer(前面讲过AsyncPagedListDiffer是一个将PagedList映射到RecyclerView.Adapter的Helper对象)对象并对其常用方法进行包装,使得它成为一个方便处理PagedList数据的适配器。
While using a LiveData<PagedList> is an easy way to provide data to the adapter, it isn't required - you can use submitList(PagedList) when new lists are available.
虽然使用LiveData<PagedList>是向适配器提供数据的一种简单方法,但这不是必需的——当有新列表可用时,可以使用submitList(PagedList)。
PagedListAdapter listens to PagedList loading callbacks as pages are loaded, and uses DiffUtil on a background thread to compute fine grained updates as new PagedLists are received.
PagedListAdapter在加载页面时侦听PagedList加载回调,并在收到新PagedList时在后台线程上使用DiffUtil计算细粒度更新。
Handles both the internal paging of the list as more data is loaded, and updates in the form of new PagedLists.
在加载更多数据时处理列表的内部分页,并以新PagedList的形式进行更新。
PagedListAdapter在构造时,需要传递一个DiffUtil.ItemCallback<T>参数,用于计算列表中两个非空项之间差异的回调。
protected PagedListAdapter(@NonNull DiffUtil.ItemCallback<T> diffCallback) {
mDiffer = new AsyncPagedListDiffer<>(this, diffCallback);
// 监听当前PagedList更新
mDiffer.addPagedListListener(mListener);
}
要实现的DiffUtil.ItemCallback的2个方法:
// 调用以检查两个对象是否表示同一项,例如,如果您的项具有唯一的id,则判断id是否一致
areItemsTheSame(@NonNull T oldItem, @NonNull T newItem)
// 调用以检查两个项是否具有相同的数据。这就得重写equals方法了。
areContentsTheSame(@NonNull T oldItem, @NonNull T newItem)
由于PagedListAdapter继承的是RecycleView.Adapter, 同时它本是也个抽象了,所以子类XXPagedListAdapter需要实现的方法有:
// 创建 ViewHolder(负责承载每个item的布局)
// 当然也可以复写getItemViewType(position)来定义多种viewType
VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
// 绑定 ViewHolder (负责将每个item的holder绑定数据)
// 这里holder就是onCreateViewHolder拿到的VH(可以复用的对象),postion为当前PagedList的索引
void onBindViewHolder(@NonNull VH holder, int position)
再来谈谈说上面说的submitList(pagedList)方法:
public void submitList(@Nullable final PagedList<T> pagedList) {
submitList(pagedList, null);
}
// 将新的PagedList传递给AsyncPagedListDiffer对象。
// 如果PagedList已经存在,将在后台线程上异步计算diff。当计算diff时,它将被应用(调度到ListUpdateCallback),新的PagedList将作为当前列表交换。
public void submitList(@Nullable final PagedList<T> pagedList,
@Nullable final Runnable commitCallback) {
if (pagedList != null) {
// 第一次提交
if (mPagedList == null && mSnapshot == null) {
mIsContiguous = pagedList.isContiguous();
} else {
// 必须保证每次提交的PagedList要么都是连续型的,要么都是非连续的。
if (pagedList.isContiguous() != mIsContiguous) {
throw new IllegalArgumentException("AsyncPagedListDiffer cannot handle both"
+ " contiguous and non-contiguous lists.");
}
}
}
// incrementing generation means any currently-running diffs are discarded when they finish
final int runGeneration = ++mMaxScheduledGeneration;
// 跟之前一样,啥也不做
if (pagedList == mPagedList) {
// nothing to do (Note - still had to inc generation, since may have ongoing work)
if (commitCallback != null) {
commitCallback.run();//不管有没有处理,都回传一下
}
return;
}
// mSnapshot可以理解为mPagedList的副本
final PagedList<T> previous = (mSnapshot != null) ? mSnapshot : mPagedList;
if (pagedList == null) {// 如果传入的为null
int removedCount = getItemCount();
if (mPagedList != null) {// 而之前的不为null,
// 移除分页加载回调监听,
// 这样后面就不会再触发onInserted(如:loadAfter)/onRemoved/onChanged这些方法执行了
mPagedList.removeWeakCallback(mPagedListCallback);
mPagedList = null;
} else if (mSnapshot != null) {
mSnapshot = null;
}
// 则移除之前加载的所有数据
// dispatch update callback after updating mPagedList/mSnapshot
mUpdateCallback.onRemoved(0, removedCount);
// 并通知当前列表更新
onCurrentListChanged(previous, null, commitCallback);
return;
}
// pagedList有数据,而mPagedList没数据 副本也没有,说明是第一次
if (mPagedList == null && mSnapshot == null) {
// fast simple first insert
mPagedList = pagedList;
pagedList.addWeakCallback(null, mPagedListCallback);
// adapter从第一行开始插入数据, 更新ui
// dispatch update callback after updating mPagedList/mSnapshot
mUpdateCallback.onInserted(0, pagedList.size());
onCurrentListChanged(null, pagedList, commitCallback);
return;
}
// pagedList有数据,mPagedList也有数据
if (mPagedList != null) {
// first update scheduled on this list, so capture mPages as a snapshot, removing
// callbacks so we don't have resolve updates against a moving target
mPagedList.removeWeakCallback(mPagedListCallback);
// 因为需要在异步线程池中比较,所以先拿一个之前的副本
mSnapshot = (PagedList<T>) mPagedList.snapshot();
mPagedList = null;
}
if (mSnapshot == null || mPagedList != null) {
throw new IllegalStateException("must be in snapshot state to diff");
}
final PagedList<T> oldSnapshot = mSnapshot;
final PagedList<T> newSnapshot = (PagedList<T>) pagedList.snapshot();
// 计算是否需要更新数据给adapter
mConfig.getBackgroundThreadExecutor().execute(new Runnable() {
@Override
public void run() {
final DiffUtil.DiffResult result;
result = PagedStorageDiffHelper.computeDiff(
oldSnapshot.mStorage,
newSnapshot.mStorage,
mConfig.getDiffCallback());
...
}
});
}
这样就基本清楚了:
PagedList :存放来自DataSource数据的实体集合;
LiveData<PagedList> livedata:添加了监听数据能力;
xxViewModel.livedata:添加又添加了数据共享能力。
基本调用:xxViewModel.livedata.observe(viewLifecycleOwner) { pagedList -> submitList(pagedList) }
小结:
1: 由LivePagedListBuilder.build的可知,DataSource是与PageList同时创建且相互关联的关系;
2: 又通过mRecycleView.adapter = pagedListAdapter, 再传给RecycleView,这样pagedListAdapter就与RecycleView进行了绑定;
3:最后 PagedListAdapter借助内部的AsyncPagedListDiffer来处理PagedList对象数据,而具体的数据data列表则由DataSource的loadXXX()接口被动触发获取并回传onResult(data列表)…最后由AsyncPagedListDiffer.mUpdateCallback触发ui更新。(透过源码可以看出,如果没有AsyncPagedListDiffer,这个PagedListAdapter就是一个普通的Adapter。)
借助AsyncPagedListDiffer&LivePagedListBuilder这两个纽带,就把PagedListAdapter、DataSource、PageList三者穿起来了。感觉Paging 组件就是谷歌用来设计给RecyclerView优化分页加载用的。
1回答
-
LovelyChubby
2022-11-22
你的逼格实在有点高,相当棒,给你点赞00
相似问题