Paging架构
再回头看一眼Paging的架构图
![v2-ff67e37ea6c8fa81028308225462891e_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/91ca8ec3a05d23fa30d71bef73ca063c.jpeg)
可以看到Paing的核心是PagedList,这个PagedList携带着一个DataSource,也即产生数据的工厂,PagedList中还有分页的配置,例如每页多少个数据,距离底部多少个数据时开始自动加载下一页数据,以及设置加载与更新UI的线程等。
从触发机制与数据流向角度看,构建PagedList是在页面初始化或者下拉刷新时,使用PagedList.Builder,传入PagedList.Config和DataSource.Factory两个对象。构造出来的PagedList对象调用Adapter.submitList方法传给Adapter,Adapter中持有传入的PagedList对象。submitList还会触发DataSource的loadInitial方法来初始化数据,其实这里初始化数据有两种形式,可以先把数据准备好再调用submitList,在loadInitial方法中直接将数据喂给callback即可,或者还可以在loadInitial方法中触发数据请求,在请求结果回调中调用callback将数据传给Adapter,这些就是触发数据加载的两种逻辑。
从上图中即可看出数据流向的逻辑,数据从DataSource中生产出来,不管是loadInitial还是loadAfter又或者是loadBefore,都是使用callback调用onResult将数据回传。
构造PagedList
![v2-20fd69fd1d2d085ebf7f4e17068b38e5_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/ff4277a0531e821d20b69b8e81839cd4.jpeg)
首先来看看PagedList的类结构,其内部有BoundaryCallback、Builder、Callback、Config四个内部类。一个一个来看具体定义
首先是BoundaryCallback,
@MainThread
public abstract static class BoundaryCallback<T> {
public void onZeroItemsLoaded() {}
public void onItemAtFrontLoaded(@NonNull T itemAtFront) {}
public void onItemAtEndLoaded(@NonNull T itemAtEnd) {}
}
把注释都删掉只下定义了3个方法,看这个类的注释,意思大概是如果将本地缓存数据当作网络数据的缓存时,用本地数据构造了一个PagedList并更新到UI上时,这时还是需要通知一下触发一下网络请求的。也就是说我们可以在将数据传给Adapter更新UI的同时异步加载网络数据,并将网络数据储存到本地,而DataSource每次只需要从本地取数据即可,而这个BoundaryCallback就是用来通知触发异步加载网络数据的。
根据调用堆栈,可发现这个onZeroItemsLoaded是在DataSource的callback.onResult中调用,且callback传回来的数据为空。下面两个方法onItemAtFrontLoaded和onItemAtEndLoaded则分别是在PagedList滑动到可自动加载下一页数据时触发。当DataSource中callback传回数据时,发现当前PagedList数据不为空,而请求传回的数据为空时,这也会被当作是可加载下一页数据。总结一下,BoundaryCallback的三个方法是在自动触发加载下一页数据时回调的,或者是当前PagedList数据不为空,也就是Adapter有内容,而新加载的数据为空时调用。从感性上来说,这个BoundaryCallback应该是一个数据加载监听的辅助接口,用于在加载数据时再异步辅助加载更多数据。
再看看这个PagedList.Builder类,这纯粹就是个Build模式类,仅仅是为了传入一个参数从而构造出一个PagedList对象。查看其build方法,限制了NotifyExecutor和FetchExecutor不能为null,最后调用了PageList.create方法,将set的参数传入,返回一个PagedList对象。在PagedList.create方法中,有两个分支,分别创建的是ContiguousPagedList和TitledPagedList。判断是dataSource.isContiguous,这个返回值表示两页之间是不是承接式的,也即两页之间的关系是不是当前页和上一页下一页这样的有关系,这样返回的是ContiguousPagedList对象,否则返回TiledPagedList对象,tiled表示是不是平铺的,也即每个Item之间确定关系,是根据item的位置关系来加载更多数据的。
再来看PagedList.Config类,这个类结构较为简单,只定义了几个字段外加一个Builder
public static class Config {
@SuppressWarnings("WeakerAccess")
public static final int MAX_SIZE_UNBOUNDED = Integer.MAX_VALUE;
public final int pageSize;
@SuppressWarnings("WeakerAccess")
public final int prefetchDistance;
@SuppressWarnings("WeakerAccess")
public final boolean enablePlaceholders;
public final int maxSize;
pageSize表示每页的item数量,prefetchDistance表示距离底部或顶部还差多少个item就开始触发loadAfter和loadBefore,enablePlaceHolder表示是否支持展示null placeholders,maxSize表示这个pageList的最大容量。
PagedList还有一个Callback的内部类
public abstract static class Callback {
public abstract void onChanged(int position, int count);
public abstract void onInserted(int position, int count);
@SuppressWarnings("unused")
public abstract void onRemoved(int position, int count);
}
只有三个方法,分别表示PagedList中的数据发生了变化、插入了数据,移除了数据。这个Callback接口只是为了监听PagedList的数据变化,AsyncPagedListDiffer对其的实现是mPagedListCallback对象,在相应的实现方法中直接调用了mUpdateCallback的相应方法,这个mUpdateCallback是AdapterListUpdateCallback类型的。在AdapterListUpdateCallback中的相应方法中,就调用了RecyclerView.Adapter的相应局部刷新api。
public final class AdapterListUpdateCallback implements ListUpdateCallback {
@NonNull
private final RecyclerView.Adapter mAdapter;
public AdapterListUpdateCallback(@NonNull RecyclerView.Adapter adapter) {
mAdapter = adapter;
}
@Override
public void onInserted(int position, int count) {
mAdapter.notifyItemRangeInserted(position, count);
}
@Override
public void onRemoved(int position, int count) {
mAdapter.notifyItemRangeRemoved(position, count);
}
@Override
public void onMoved(int fromPosition, int toPosition) {
mAdapter.notifyItemMoved(fromPosition, toPosition);
}
@Override
public void onChanged(int position, int count, Object payload)