本文根据以下思路进行Paging的学习:
Paging介绍Paing核心组件总结梳理许多应用程序使用包含大量项目的数据源中的数据,但一次只显示一小部分。
分页库可帮助您的应用观察并显示此数据的合理子集。此功能有几个优点:
数据请求消耗的网络带宽更少,系统资源更少。拥有计量或小数据计划的用户会欣赏这些具有数据意识的应用程序。即使在数据更新和刷新期间,应用程序仍会继续快速响应用户输入。来源自官方翻译
简单点说, Paging给开发者提供了更为便捷的RecycleView数据加载方式。
便捷的分页加载方式,应用内存压力小,网络压力更小(分成几次加载,肯定比一次加载好,现有模式就是这样)用户体验好,无感数据加载,形成信息流。激发用户探索欲望。(这也是我们为什么选择他的一部分原因),嗯,确实逐步并优雅。下图表示Paging工作中数据的流向。
注:想一下水泵抽水过程。螺旋桨吸水、滤网过滤、组建水泵。
同时,Paging把大部分的工作都放在了子线程做,UI线程只负责数据的显示。
获取数据的类,Paging提供了三种不同的分页方式:PageKeyedDataSource、PositionalDataSource、ItemKeyedDataSource。
通常使用在论坛,贴吧中。根据传入的页面num进行获取某一页的数据,比如获取第10页。
Android开发中经常使用的分页,例如,每页10条,默认显示第一页。 CONTENT_LENGTH=10、mPage=1。
使用上一条data对象里某一个值作为下一页请求的关键字。这种情况多出现在服务端已经完成了分页效果,在某一个对象添加如“下一页”这样的标识数据。
上述组件根据业务逻辑不通使用不同类型。常用的为PositionalDataSource
使用以上之一的数据加载源需要跟下一个组件进行组合配置使用。
PageList提供了一系列的配置接口,方便开发者便捷的应付变幻莫测的需求。
使用PagedList.Config 提供的接口进行配置。
/** * When {@link #maxSize} is set to {@code MAX_SIZE_UNBOUNDED}, the maximum number of items * loaded is unbounded, and pages will never be dropped. */ // MAX_SIZE=MAX_SIZE_UNBOUNDED的情况,数据会一直加载 @SuppressWarnings("WeakerAccess") public static final int MAX_SIZE_UNBOUNDED = Integer.MAX_VALUE; /** * Size of each page loaded by the PagedList. */ // 每个界面加载数据的长度 CONTENT_LENGTH public final int pageSize; /** * Prefetch distance which defines how far ahead to load. * <p> * If this value is set to 50, the paged list will attempt to load 50 items in advance of * data that's already been accessed. * * @see PagedList#loadAround(int) */ // 预加载 数据长度。 设置为50,当你看到第一个数据时候,第50条数据已加载完成 @SuppressWarnings("WeakerAccess") public final int prefetchDistance; /** * Defines whether the PagedList may display null placeholders, if the DataSource provides * them. */ // 数据没有加载成功时候,底部的占位符,相当于"加载更过" @SuppressWarnings("WeakerAccess") public final boolean enablePlaceholders; /** * Defines the maximum number of items that may be loaded into this pagedList before pages * should be dropped. * <p> * {@link PageKeyedDataSource} does not currently support dropping pages - when * loading from a {@code PageKeyedDataSource}, this value is ignored. * * @see #MAX_SIZE_UNBOUNDED * @see Builder#setMaxSize(int) */ // 最大加载量,数据加载到最大量之后,将会删除 public final int maxSize; /** * Size hint for initial load of PagedList, often larger than a regular page. */ // 一个提示大小 @SuppressWarnings("WeakerAccess") public final int initialLoadSizeHint;上述的配置已经满足我们基本需求,根据不同的场景设置不同的pageSize,达到更好的用户体验。
上面我们已经讲过了两个组件,分别是DataSource(螺旋桨)、PagedList(过滤网)。
接下来我们就要把这些组装起来,完成build过程。 该组件提供构造函数满足我们组件的需求,
mLiveData = new LivePagedListBuilder(new PageDataSourceFactory(positionalDataSource) , new PagedList.Config.Builder().setPageSize(CONTENT_LENGTH) .setPrefetchDistance(CONTENT_LENGTH) .setEnablePlaceholders(false).setInitialLoadSizeHint(CONTENT_LENGTH) .build()).build();可以看到,通过该类的构造函数,将DataSource与PagedList绑定在一起,完成build.
那这个Builder返回的对象是一个什么样的类型呢???
LiveData<PagedList<GankData>> mLiveData分页库实现了应用程序体系结构指南中建议的观察者模式 。特别是,库的核心组件创建LiveDataUI可以观察的实例 (或等效的基于RxJava2的类)。然后,您的应用程序的UI可以PagedList在生成对象时显示对象中的内容 ,同时尊重UI控制器的 生命周期。
返回的是一个LiveData类型的对象。他负责把获取的数据发送给到主线程。(水泵口接上了水管)。
注:还有一个需要注意的是RecycleView的adapter需要继承Paging自定义的PageAdapter。
public class MyAdapter extends PagedListAdapter<GankData, BaseViewHolder> { private Context mContext; protected MyAdapter(@NonNull DiffUtil.ItemCallback<GankData> diffCallback) { super(diffCallback); } @NonNull @Override public BaseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { mContext = parent.getContext(); return new BaseViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_main, parent, false)); } @Override public void onBindViewHolder(@NonNull BaseViewHolder holder, int position) { TextView tvName = holder.getView(R.id.tv_name); ImageView imageView = holder.getView(R.id.iv); GankData data = getItem(position); tvName.setText(position+""); GlideUtils.loadImage(mContext,imageView,data.getUrl()); } }优点:Paging使得分页变得逻辑清晰、高效、便捷、优雅。同时又提升了用户体验。被分页问题搞到的同学可以尝试使用Paging作为解决方案。
缺点:配置相对繁琐,不同的界面界面的代码相对增加,初次使用比较麻烦(再加上AndroidX的刺激问题)
好了,Paging的初识至此告一段落,下一步我们来上手使用,感受以下它的魅力。