Android Architecture Paging Library详解 | Google I/O大会上的最新发布

作 者 简 介

郭海生

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 允许内容的分页,但是都有明显的限制和缺陷:

  • CursorAdapter(https://developer.android.com/reference/android/widget/CursorAdapter.html)使得获取数据库查询结果更加容易的映射到ListView项目中,但是它的查询操作是在UI线程上运行的,并且以低效的方式使用Cursor。
  • AsyncListUtil(https://developer.android.com/reference/android/support/v7/util/AsyncListUtil)允许把基于位置position的数据分页放进RecyclerView,但是不支持非位置position的数据,并且强制空数据集中的空位占位符。

>>>>

Paging Library详解

>>>> 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 Library 库的架构

从图中可以看出,Paging是围绕PagedList为中心的,遵循数据驱动的思想。

>>>> DataSource

DataSource<Key,Value>是PagedList的数据源类。Key相当于加载数据的条件信息,Value对应返回的结果。Paging提供了三种DataSource<Key,Value>的实现:

  1. PageKeyedDataSource<Key,Value>:适用于以页信息加载数据的场景。比如在网络加载数据的时候,需要传Next或者Previous作为键值参数。
  2. ItemKeyedDataSource<Key,Value>:适用于所加载的数据依赖其他现有数据信息的场景。比如加载第N+1条需要第N条的数据,这时候需要传第N条的数据过去。
  3. PositionalDataSource<T>:适用于数据总量固定,支持从特定位置加载数据的场景。比如返回从1200条开始的200条数据。

三种DataSource相同点:都有loadInitial()抽象方法,各自都封装了请求初始化数据的参数类型LoadInitialParams和接受请求参数的LoadInitialCallback。

不同点:PageKeyedDataSource和ItemKeyedDataSource需要实现loadBefore()和loadAfter()方法,而PositionalDataSource需要实现loadRange()方法。

可以看出,DataSource不是真正的数据源,而是负责从数据源加载数据,承担了PagedList与数据源之间的桥梁。

>>>> PagedList

PagedList从DataSource中获取数据,通过PagedList.Config 可以配置一次加载的数量以及预加载的数量,它也为RecyclerView.Adapter提供更新信号,驱动UI的刷新。它提供了五个成员变量如下:

  • mMainThreadExecutor:主线程的Executor, 可以将结果post到主线程。
  • mBackgroundThreadExecutor:后台线程的Executor。
  • BoundaryCallback:加载Datasource中的数据加载到边界时的回调。

PagedList.Config可配置的属性:

  1. setPageSize:设置每页加载的数量。
  2. setInitialLoadSizeHint:初始化数据时候加载数量。
  3. setPrefetchDistance:预加载数量,设置距离最后还剩多少个item开始加载下一页的数据。
  4. setEnablePlaceholders:当Item为null时是否使用PlaceHolder展示。
  5. PagedStorage<T>:用于存储加载到的数据,它包含一个ArrayList<List<T>>对象mPages,按页存储数据。

>>>> PagedListAdapter

PagedListAdapter继承于RecycleView.Adapter,用来在RecycleView中显示PagedList 的数据。当拖动RecycleView加载每一页数据的时候,PagedListAdaptert通过DiffUtil在后台线程计算PagedList细粒度的变化并返回给自己一个新的PagedList,然后调用自己的notifyItem……()做刷新等操作。

>>>> AsyncPageListDiffer

AsyncPageListDiffer是一个辅助类,可以将PagedList数据更方便的映射到PagedListAdapter里。我们通常都是用LiveData承载PagedList对象,当数据变化的时候通过Lifecycles能收到通知,我们可以调用PagedListAdapter的submitList(PagedList)方法更新数据。AsyncPageListDiffer能监听到PagedList的加载Callbacks,通过DiffUtils在后台线程可拿到最新的数据集合。AsyncPageListDiffer为我们提供了getItem(int)和getItemCount()方法,这个可以配合PagedListAdapter呈现数据。

>>>> Paging Library 加载数据流程

如上图所示,Paging加载数据是在后台线程进行的,加载完成后在主线程显示。

当创建LiveData<PagedList>时候,LiveData会新建一个线程从DataSource中加载数据(触发loadInitial()),DataSource加载到数据会更新PagedList,PagedList更新会通知PagedAdapter,PagedAdapter会利用DiffUtil对比现在的Item和更新的Item的差异,对比结束后会确定是否刷新UI。

刷新UI,UI显示会触发PagedAdapter的getItem操作,随即触发PagedList的loadAround方法从DataSource加载周围的数据。

可以看出,整个过程Paging内部实现了线程的切换,数据的预加载,所有联动都是在Paging中,使用者只用关心加载数据的具体实现。

>>>> Paging Library的使用方法

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---------------------

原文发布于微信公众号 - 京东技术(jingdongjishu)

原文发表时间:2018-07-17

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Android群英传

Android NDK层发起HTTP请求的问题及解决

1042
来自专栏FreeBuf

PHP代码审计实战思路浅析

对于面向过程写法的程序来说,最快的审计方法可能时直接丢seay审计系统里,但对于基于mvc模式的程序来说,你直接丢seay审计系统的话,那不是给自己找麻烦吗?

1193
来自专栏BeJavaGod

通过spring实现javamail的那些事儿

以前很早的时候大家都用javamail实现发送邮件的功能,而且我们也一直沿用至今,代码拷过来用用就行了,现在我们改为用spring来实现,这样一来减少代码的复杂...

2954
来自专栏北京马哥教育

服务器病了吗? Linux 服务器的那些性能参数指标

2622
来自专栏北京马哥教育

Linux内存被吃掉了,它去哪里了?

在Windows下资源管理器查看内存使用的情况,如果使用率达到80%以上,再运行大程序就能感觉到系统不流畅了,因为在内存紧缺的情况下使用交换分区,频繁地从磁盘上...

1332
来自专栏生信宝典

上传高通量测序原始文件

在我们发表高通量测序文章之前通常要上传测序数据到GEO数据库,现总结流程如下。 注册账户、填写MetaSheet 在NCBI GEO官网注册一个账号,然后登陆。...

2739
来自专栏Vamei实验室

被解放的姜戈01 初试天涯

Django是Python下的一款网络服务器框架。Python下有许多款不同的框架。Django是重量级选手中最有代表性的一位。许多成功的网站和APP都基于Dj...

1.8K6
来自专栏腾讯移动品质中心TMQ的专栏

Android内存泄露测试不再蓝瘦,香菇

在进行Android内存泄露分析时,面对成千上万个对象,你是否蓝瘦,香菇?作为测试人员你在进行内存泄露测试之后,是否有勇气告诉开发同事程序已经没有内存泄露,可以...

2777
来自专栏大数据文摘

业界 | Dropbox力荐!我们如何应对Python桌面应用程序的崩溃

揭秘Crashpad系统如何帮助Dropbox这样复杂的桌面程序捕获并报告崩溃,且兼容Python的多种语言。

841
来自专栏owent

近期的一个协程流程BUG

最近一直没什么时间整理近期碰到的问题,今天思考了一下之前碰到的一个临时处理的BUG,顺便写点东西清理一下思路。

692

扫码关注云+社区

领取腾讯云代金券