作 者 简 介
郭海生
Android高级工程师,6年以上开发经验,有丰富的代码重构和架构设计经验,负责京东商城我的京东的开发工作,热衷于学习和研究新技术。
>>>>
导读
美国当地时间2018年5月8日,Google I/O大会上发布了 Android Jetpack 。将之前发布的一系列组件比如 Lifecycle、LiveData、Room、ViewModel等进行融合从而推出了一套官方认证的开发体系Android Jetpack。这套体系分为架构(Architecture)、UI、基础(Foundation)以及行为(Behavior)四个方面。
谷歌官方架构组件图:
这次的Android Jetpack推出了五个新组件,它们分别是:Navigation(导航组件)、Paging(分页组件)、WorkManager(处理类似后台任务组件)、Slices(切片)、Android KTX(Kotiln扩展程序)
本文主要介绍的是Paging,关于Navigation的解析,可以查看《Android Jetpack 新组件之Navigation的用法和源码结构分析》
>>>>
背景
现有的 Android API 允许内容的分页,但是都有明显的限制和缺陷:
>>>>
Paging Library详解
“The Paging Library makes it easier for youto load data gradually and gracefully within your app's RecyclerView.
Many apps consume data from a data sourcethat contains a large number of items, but only display a small portion at atime.
The Paging Library helps your app observeand display a reasonable subset of this data.”
【翻译】:
Paging library 可以让你渐进的加载数据到你的数据源,而且可以优雅的配合RecyclerView使用。
许多app经常性从大量数据源里加载数据,但是在某个时刻却只需要展示这些数据的一小部分。Paging library可以帮助你的app观察和展示一个合理的数据集合。
从图中可以看出,Paging是围绕PagedList为中心的,遵循数据驱动的思想。
DataSource<Key,Value>是PagedList的数据源类。Key相当于加载数据的条件信息,Value对应返回的结果。Paging提供了三种DataSource<Key,Value>的实现:
三种DataSource相同点:都有loadInitial()抽象方法,各自都封装了请求初始化数据的参数类型LoadInitialParams和接受请求参数的LoadInitialCallback。
不同点:PageKeyedDataSource和ItemKeyedDataSource需要实现loadBefore()和loadAfter()方法,而PositionalDataSource需要实现loadRange()方法。
可以看出,DataSource不是真正的数据源,而是负责从数据源加载数据,承担了PagedList与数据源之间的桥梁。
PagedList从DataSource中获取数据,通过PagedList.Config 可以配置一次加载的数量以及预加载的数量,它也为RecyclerView.Adapter提供更新信号,驱动UI的刷新。它提供了五个成员变量如下:
PagedList.Config可配置的属性:
PagedListAdapter继承于RecycleView.Adapter,用来在RecycleView中显示PagedList 的数据。当拖动RecycleView加载每一页数据的时候,PagedListAdaptert通过DiffUtil在后台线程计算PagedList细粒度的变化并返回给自己一个新的PagedList,然后调用自己的notifyItem……()做刷新等操作。
AsyncPageListDiffer是一个辅助类,可以将PagedList数据更方便的映射到PagedListAdapter里。我们通常都是用LiveData承载PagedList对象,当数据变化的时候通过Lifecycles能收到通知,我们可以调用PagedListAdapter的submitList(PagedList)方法更新数据。AsyncPageListDiffer能监听到PagedList的加载Callbacks,通过DiffUtils在后台线程可拿到最新的数据集合。AsyncPageListDiffer为我们提供了getItem(int)和getItemCount()方法,这个可以配合PagedListAdapter呈现数据。
如上图所示,Paging加载数据是在后台线程进行的,加载完成后在主线程显示。
当创建LiveData<PagedList>时候,LiveData会新建一个线程从DataSource中加载数据(触发loadInitial()),DataSource加载到数据会更新PagedList,PagedList更新会通知PagedAdapter,PagedAdapter会利用DiffUtil对比现在的Item和更新的Item的差异,对比结束后会确定是否刷新UI。
刷新UI,UI显示会触发PagedAdapter的getItem操作,随即触发PagedList的loadAround方法从DataSource加载周围的数据。
可以看出,整个过程Paging内部实现了线程的切换,数据的预加载,所有联动都是在Paging中,使用者只用关心加载数据的具体实现。
1、Gradle依赖
https://developer.android.com/topic/libraries/architecture/adding-components#paging
2、构造可观察的PagedList对象
userDao是model对象,可以从数据库取到User返回DataSource.Factory对象,我们将DataSource.Factory传给LivePagedListBuilder,并配置PagedList,可以返回一个LiveData对象
3、构建数据源对象
我们用DataSource建立分页数据源,实现了ItemKeyedDataSource对应的抽象方法,定义加载第一页以及后面每一页数据。
4、PagedListAdpater建立与数据的绑定
5、MainActivity初始化UI、订阅数据源状态从而更新UI
>>>>
总结
Paging Library通过配合Lifecycle、ViewModel、LiveData等组件的特性,为我们提供了一个简单、安全、灵活的分页加载组件,其核心思想上以数据为驱动,我们只需关心加载数据的具体实现,并且在用户体验上,Paging Library逐步从数据源加载信息,从而不会耗费过多的设备资源或是等待太长的时间。
>>>>
具体使用方法请参考
官网:
https://developer.android.com/topic/libraries/architecture/paging/
googlecodelabs关于paginglibrary的使用方法:
https://codelabs.developers.google.com/codelabs/android-paging/index.html
官方demo:
https://github.com/googlesamples/android-architecture-components/tree/master/PagingWithNetworkSample
特别鸣谢:
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2017/0920/8533.html
---------------------END---------------------