Android 官方全新推荐组件:Paging Library 基于RecyclerView的分页加载框架

作者:Adan0520 (文末附Demo源码地址)

一、概述

在2018年5月9日的谷歌开发者大会(Google I/O 2018) 中提出在去年发布的广受欢迎的架构组件上,进一步改进并推出了Jetpack。Jetpack能帮助我们更专注提升应用体验,加快应用开发速度,处理类似后台任务、UI 导航以及生命周期管理等。发布的新版 Android Jetpack 组件中更新的内容包括 4 个部分:WorkManager、Paging、Navigation 以及 Slices。我们今天要说的就是Paging,在进行大数据查询的时候,Paging分页组件可以让我们从本地或者网络中通过渐进的方式、逐步的请求数据加载,在不过多增加设备负担或等待时间的情况下,让应用拥有了处理大型数据的能力,其中包括对RecycleView的支持。和往常一样,主要是想总结一下Android官方Paging Library的学习过程以及一些需要注意的地方。

详细请查看谷歌官方文档:https://developer.android.com/topic/libraries/architecture/paging/

二、Paging Libray介绍

2.1、Paging Library中DataSource,PagedList,PagedAdapter三者之间的关系以及数据加载到数据展示的流程:

(1)如下图所示,Paging的数据流是在后台线程生产的,在后台线程中完成了大部分工作,在UI线程中显示。

比如说:当一条新的item插入到数据库,DataSource会被初始化,LiveData后台线程就会创建一个新的PagedList。这个新的PagedList会被发送到UI线程的PagedListAdapter中,PagedListAdapter使用DiffUtil在对比现在的Item和新建Item的差异。当对比结束,PagedListAdapter通过调用RecycleView.Adapter.notifyItemInserted()将新的item插入到适当的位置。RecycleView就会知道它需要绑定一个新的item,并将其显示。

(2)从代码层面来说,我们需要给Recyclerview设置PagedListAdater,PagedListAdapter设置对应的PagedList。每一次adapter getItem就是让PagedList知道我们已经滑到第几个item了,PagedList计算这些数量以及配置的参数,当条件达成就通知DataSource,让其返回数据。数据返回成功时,通知PagedListAdapter进行刷新等操作。

2.2、Datasource

Datasource是数据源相关的类,针对不同场景,Paging 提供了三种 Datasource:

(1)PageKeyedDataSource:如果页面在加载时插入一个/下一个键,例如:从网络获取社交媒体的帖子,可能需要将nextPage加载到后续的加载中;

(2)ItemKeyedDataSource:在需要让使用的数据的item从N条增加到N+1条时使用;

(3)PositionalDataSource:如果需要从数据存储的任意位置来获取数据页面。此类支持你从任何位置开始请求一组item的数据集。例如,该请求可能会返回从位置1200条开始的20个数据项;

根据使用场景选择实现DataSource不同的抽象类, 使用时需实现请求加载数据的方法。其中这三种Datasource 都需要实现 loadInitial()方法, 各自都封装了请求初始化数据的参数类型 LoadInitialParams。 不同的是分页加载数据的方法, PageKeyedDataSource和 ItemKeyedDataSource比较相似, 需要实现 loadBefore()和 loadAfter()方法,同样对请求参数做了封装,即 LoadParams。 PositionalDataSource需要实现 loadRange()

2.3、PagedList

PagedList 通过 Datasource 加载数据, 通过 Config 的配置,可以设置一次加载的数量以及预加载的数量等。 除此之外,PagedList 还可以向 RecyclerView.Adapter 发送更新UI的信号。

Config: 配置 PagedList 从 Datasource 加载数据的方式, 其中包含以下属性:

-setPageSize:设置每一页加载的数量;

-setInitialLoadSizeHint:设置首次加载的数量;

-setPrefetchDistance:设置距离最后还有多少个item时,即寻呼库开始加载下一页的数据;

-setEnablePlaceholders:表示是否设置null占位符;

2.4、PagedListAdapter

PagedListAdapter 是 RecyclerView.Adapter 的实现,用于展示 PagedList 的数据。PagedListAdapter中每一次getItem就是让PagedList知道我们已经滑到第几个item了,当数据源提供新的PagedList时,PagedList会计算这些数量以及配置的参数,当条件达成就通知DataSource,让其返回数据。数据返回成功时,通知PagedListAdapter。 而PagedListAdapter会使用DiffUtil再对比现在的Item和新建Item的差异并进行刷新等操作

三、加载的数据源类型

数据的加载方式主要有两种:

3.1、单一数据源:本地数据或网络数据

首先我们可以通过 LivePagedListBuilder来创建 LiveData为 UI 层提供数据。如果数据源是DB,当数据发生变化,DB 会推送一个新的 PagedList(依赖LiveData的机制)。如果是网络数据,因为我们无法知道数据源的变化,以通过滑动刷新的方式调用 Datasource 的 invalidate()方法来加载新的数据。流程如下所示:

3.2、多个数据源:本地数据+网络数据

一般是先加载本地数据,加载完成后再加载网络数据。比如 IM 中的聊天消息,当打开聊天界面时先加载本地数据库中的聊天消息,加载完了再加载网络的离线消息。这个时候我们需要为 PagedList 设置 BoundaryCallback来监听本地数据是否加载完成,当本地数据加载完成就触发加载网络数据,然后入库,此时LiveData会推送一个新的PagedList, 并触发界面刷新。

四、代码的实现

按照惯例,我们先来看看效果图

从效果图中可以看到,当RecyclerView不断下滑时,就触发分页加载,把RecyclerView后续要使用的数据分页加载显示出来。这么说吧,当我们滑动第一页时,在还没有滑到底部的时候,它将请求第二页的数据,代码中就是实现ItemKeyedDataSource中的loadAfter方法;当我们滑动第二页时,在还没有滑到底部的时候,它将请求第三页的数据,以此类推。好了,下面我们来看看代码吧

1、首先要使用Android Paging Library,我们需要在应用的build.gradle中添加Paging支持库以及我在Dome中用到的其他库的引用(注意:这篇文章是基于Paging Library 1.0.0的版本。):

2、StudentDataSourceFactory:

为了创建这些可观察 PagedList对象,我们需要将DataSource.Factory给一个LivePagedListBuilder对象。一个DataSource对象为单个页面加载PagedList数据。工厂类创建新的实例PagedList以响应内容更新,例如数据库表失效和网络刷新。

3、StudentDataRepository:

4、定义一个用于给不同的Repository实现共享的通用接口

5、选择正确的数据源类型

下面,我们就使用DataSource建立自己的分页数据源,其中包括定义加载第一页以及后面每一页数据

这里的实现了ItemKeyedDataSource中几个方法:

(1)loadInitial(@NonNull LoadInitialParams params,@NonNull LoadInitialCallback callback)

->用于接收初始第一页加载的数据,在这里需要将获取到的数据通过LoadInitialCallback的onResult进行回调,用于出始化PagedList,并对加载的项目进行计数

(2)loadAfter(@NonNull LoadParams params,@NonNull LoadCallback callback)

->用于接收后面每一页加载的数据,使用方法和loadInitial一样

(3)loadBefore(@NonNull LoadParams params,@NonNull LoadCallback callback)

->指定的密钥之前加载列表数据

(4)getKey(@NonNull Value item)

->返回与给定项目关联的密钥

6、Listing,用于UI显示列表和系统其余部分进行交互所必需的数据类

7、Resource,一个通用类,用于保存具有其加载状态的值

8、StudentViewModel

在Dome中我们是引用MVVM的应用框架,StudentViewModel只做和业务逻辑和业务数据相关的事,不做任何和UI相关的事情,负责完成View与Model间的交互。ViewModel 层不会持有任何控件的引用,更不会在ViewModel中通过UI控件的引用去做更新UI的事情。简单说就是专注于业务的逻辑处理,做的事情也都只是对数据的操作。后面我可能会专门写一篇MVVM的文章

9、MainActivity,这里的Activity做的事就是初始化一些控件(如控件的颜色,添加RecyclerView的分割线等)、订阅Resource.Status的加载状态,从而更新UI。简单地说:View层不做任何业务逻辑、不涉及操作或处理数据。

10、StudentAdapter:

大概就这么多,我把现阶段对Android Paging Library学习过程记录下来,作为我学习Android Paging Library技术的阶段性备忘录,这代码还有待进一步完善和继续跟进研究!

有什么疑问的,请在下面留言,有不足之处还望指导,感谢各位^_^

附录:

1、谷歌Android官方Android Paging Library技术文档主页:

https://developer.android.com/topic/libraries/architecture/paging/

2、Google samples :

https://github.com/googlesamples/android-architecture-components

最后,欢迎大家加入我们的知识星球,这期是到2019年3月10日结束,所以越早加入越好,现在加入的球友快1000人了,到1000人时将大幅提价(还有最后几十个名额了),所以快上车!

  • 发表于:
  • 原文链接:https://kuaibao.qq.com/s/20180806B00O2800?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券