Android(安卓)Paging - PagedListAdapter
16lz
2022-07-05
简介
Android JectPack 组件中Paging 是其中一个重要组件。Paging 是对RecyclerVew.adpater的扩展。本文介绍其中一个知识点,用于记录自己的学习历程。
Adapter
RecyclerView是Android中的一个重要组件,使用RecyclerView组件最为重要的一个是自定义Adapter。如果使用Paging需要继承PagedListAdapter。一般自定义Adapter代码如下。
public class CheeseAdapter extends PagedListAdapter { private static DiffUtil.ItemCallback diffCallBack = new DiffUtil.ItemCallback() { @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 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 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) mPagedList.snapshot(); mPagedList = null; } if (mSnapshot == null || mPagedList != null) { throw new IllegalStateException("must be in snapshot state to diff"); } final PagedList oldSnapshot = mSnapshot; final PagedList newSnapshot = (PagedList) 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执行差分更新。
更多相关文章
- 类和 Json对象
- Andorid Dialog 示例【慢慢更新】
- Android中文API(144) —— JsonWriter
- Android(安卓)SDK Manager无法更新的解决
- Android热更新框架Tinker无法更新?
- Android之Handler用法总结
- android通过ksoap2对webservice的解析
- Android,一个思路实现APP版本更新
- Android(安卓)View的介绍和使用