简介
Android JectPack 组件中Paging 是其中一个重要组件。Paging 是对RecyclerVew.adpater的扩展。本文介绍其中一个知识点,用于记录自己的学习历程。
Adapter
RecyclerView是Android中的一个重要组件,使用RecyclerView组件最为重要的一个是自定义Adapter。如果使用Paging需要继承PagedListAdapter。一般自定义Adapter代码如下。
public class CheeseAdapter extends PagedListAdapter<Cheese,CheeseViewHolder> {
private static DiffUtil.ItemCallback<Cheese> diffCallBack = new DiffUtil.ItemCallback<Cheese>() {
@Override
public boolean areItemsTheSame(@NonNull Cheese oldItem, @NonNull Cheese newItem) {
return oldItem.getId() == newItem.getId();
}
@Override
public boolean areContentsTheSame(@NonNull Cheese oldItem, @NonNull Cheese newItem) {
return oldItem.getName().equals(newItem.getName());
}
};
public CheeseAdapter() {
super(diffCallBack);
}
@NonNull
@Override
public CheeseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new CheeseViewHolder(parent);
}
@Override
public void onBindViewHolder(@NonNull CheeseViewHolder holder, int position) {
holder.bindTo(getItem(position));
}
}
其中Cheese是自定义的显示item类,CheeseViewHolder是ViewHolder。
PagedListAdapter 简易类图
- PagedListAdapter 继承于RecyclerView.Adapter。表明这是一个RecyclerView.Adapter,并且扩展了RecyclerView.Adapter的功能。
- 扩展功能是支持异步差分更新功能。
装饰器模式
装饰器模式(Decorator Pattern),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器模式比生成子类更灵活。 ----《大话设计模式》
标准的装饰器模式类图
- 被装饰对象抽象接口(Component)
- 具体的被装饰对象(ConcreteCompoent),负责接收装饰器。
- Decorator装饰角色。持有一个抽象构件的引用。装饰对象接受所有客户端的请求,并把这些请求转发给真实的对象。这样,就能在真实对象调用前后增加新的功能
- ConcreteDecorate具体装饰角色:负责给构件对象增加新的功能。
小结
可以通过装饰器模式对PagedListAdapter进行拆分理解,PagedListAdapter添加了异步差分更新内容。
更新流程
更新数据PagedList
PagedList 继承 AbstractList。说明这个是一个list。PagedList的功能参见源码的注释。
个人理解如下:
- pagedList 可以在多个线程进行传递和访问。
- 初始化之后,pagedList被UI主线程持有。
PagedList 初始化
Pagedlist 的初始化与DataSource 有关。当xxDataSource 重新isContiguous 为true是,初始化的是ContiguousPagedList。否则初始化为TiledPagedList。
更新具体流程
更新流程的接口调用关系是
- PagedListAdapter#submitList
- AsyncPagedListDiffer#submitList
- AdapterListUpdateCallback#onInserted 或者 onRemoved或者onMoved 或者onChanged
- RecyclerView.Adapter 的notifyItemxx通知接口
核心代码如下
public void submitList(@Nullable final PagedList<T> pagedList,
@Nullable final Runnable commitCallback) {
if (pagedList != null) {
// 判断submit 的pagedList 是否和 已持有的pagedList 是同类型的
if (mPagedList == null && mSnapshot == null) {
mIsContiguous = pagedList.isContiguous();
} else {
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) {
// submit 的 pagedList 和当前持有的 pagedList相同,不做任何操作直接返回
// nothing to do (Note - still had to inc generation, since may have ongoing work)
if (commitCallback != null) {
commitCallback.run();
}
return;
}
final PagedList<T> previous = (mSnapshot != null) ? mSnapshot : mPagedList;
if (pagedList == null) {
// submit 的 pagedList 为空,执行移除操作
int removedCount = getItemCount();
if (mPagedList != null) {
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;
}
if (mPagedList == null && mSnapshot == null) {
// 为持有 pagedList 则将 submit 的pagedList 直接插入
// fast simple first insert
mPagedList = pagedList;
pagedList.addWeakCallback(null, mPagedListCallback);
// dispatch update callback after updating mPagedList/mSnapshot
mUpdateCallback.onInserted(0, pagedList.size());
onCurrentListChanged(null, pagedList, commitCallback);
return;
}
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();
mConfig.getBackgroundThreadExecutor().execute(new Runnable() {
@Override
public void run() {
final DiffUtil.DiffResult result;
result = PagedStorageDiffHelper.computeDiff(
oldSnapshot.mStorage,
newSnapshot.mStorage,
mConfig.getDiffCallback());
mMainThreadExecutor.execute(new Runnable() {
@Override
public void run() {
if (mMaxScheduledGeneration == runGeneration) {
latchPagedList(pagedList, newSnapshot, result,
oldSnapshot.mLastLoad, commitCallback);
}
}
});
}
});
}
更新流程如下:
- 如果submit的pagedList 为null ,则直接移除Adapter显示数据。
- 如果submit的pagedList不为null,且Adapter持有的padedList为null,则执行插入数据操作,通过Adapter更新UI界面。
- 如果submit的pagedList不为null,且Adapter持有的padedList不为null,则通过DiffUtil执行差分更新。