Paging 2 库概览 Android Jetpack 的一部分。
Paging 库可帮助您一次加载和显示多个小的数据块。按需载入部分数据会减少网络带宽和系统资源的使用量。
本指南提供了该库的几个概念性示例,并概述了相应的运作方式。如需查看此库运作方式的完整示例,请尝试其他资源部分中的 Codelab 和示例。
设置
如需将 Paging 组件导入到 Android 应用中,请将以下依赖项添加到应用的 build.gradle 文件中:
Groovy
dependencies { def paging_version = "2.1.2" implementation "androidx.paging:paging-runtime:$paging_version" // For Kotlin use paging-runtime-ktx // alternatively - without Android dependencies for testing testImplementation "androidx.paging:paging-common:$paging_version" // For Kotlin use paging-common-ktx // optional - RxJava support implementation "androidx.paging:paging-rxjava2:$paging_version" // For Kotlin use paging-rxjava2-ktx }
Kotlin
dependencies { val paging_version = "2.1.2" implementation("androidx.paging:paging-runtime:$paging_version") // For Kotlin use paging-runtime-ktx // alternatively - without Android dependencies for testing testImplementation("androidx.paging:paging-common:$paging_version") // For Kotlin use paging-common-ktx // optional - RxJava support implementation("androidx.paging:paging-rxjava2:$paging_version") // For Kotlin use paging-rxjava2-ktx }
库架构
本节介绍并展示 Paging 库的主要组件。
PagedList
Paging 库的关键组件是 PagedList 类,用于加载应用数据块(即页面)。随着所需数据的增多,系统会将其分页到现有的 PagedList 对象中。如果任何已加载的数据发生更改,会从基于 LiveData 或 RxJava2 的对象向可观察数据存储器发出一个新的 PagedList 实例。随着 PagedList 对象的生成,应用界面会呈现其内容,同时还会考虑界面控件的生命周期。
以下代码段展示了如何配置应用的视图模型,以便使用 PagedList 对象的 LiveData 存储器加载和显示数据:
Kotlin
class ConcertViewModel(concertDao: ConcertDao) : ViewModel() { val concertList: LiveData<PagedList<Concert>> = concertDao.concertsByDate().toLiveData(pageSize = 50) }
Java
public class ConcertViewModel extends ViewModel { private ConcertDao concertDao; public final LiveData<PagedList<Concert>> concertList; // Creates a PagedList object with 50 items per page. public ConcertViewModel(ConcertDao concertDao) { this.concertDao = concertDao; concertList = new LivePagedListBuilder<>( concertDao.concertsByDate(), 50).build(); } }
数据
每个 PagedList 实例都会从对应的 DataSource 对象加载应用数据的最新快照。数据从您应用的后端或数据库流向 PagedList 对象。
以下示例使用 Room 持久性库来整理应用数据,但如果要通过其他方式存储数据,也可以提供自己的数据源工厂。
Kotlin
@Dao interface ConcertDao { // The Int type parameter tells Room to use a PositionalDataSource object. @Query("SELECT * FROM concerts ORDER BY date DESC") fun concertsByDate(): DataSource.Factory<Int, Concert> }
Java
@Dao public interface ConcertDao { // The Integer type parameter tells Room to use a // PositionalDataSource object. @Query("SELECT * FROM concerts ORDER BY date DESC") DataSource.Factory<Integer, Concert> concertsByDate(); }
如需详细了解如何将数据加载到 PagedList 对象中,请参阅有关如何加载分页数据的指南。
界面
PagedList 类使用 PagedListAdapter 将项加载到 RecyclerView。这些类共同作用,在内容加载时抓取和显示内容,预取视图之外的内容以及针对内容更改添加动画效果。
如需了解详情,请参阅有关如何显示分页列表的指南。
支持不同的数据架构
Paging 库支持以下数据架构:
- 仅从后端服务器提供。
- 仅存储在设备上的数据库中。
- 使用设备上的数据库作为缓存的其他来源组合。
图 1 展示了这些架构场景中的数据流动情况。对于仅限网络或仅限数据库的解决方案,数据会直接流向应用界面模型。如果您使用的是组合方式,数据会从您的后端服务器流向设备上的数据库,然后流向应用界面模型。每隔一段时间,每个数据流的端点就会耗尽要加载的数据,此时它会从提供数据的组件请求更多数据。例如,当设备上的数据库耗尽数据时,它会从服务器请求更多数据。
本部分的其余内容提供了有关如何配置各个数据流使用场景的建议。
仅限网络
如需显示来自后端服务器的数据,请使用同步版本的 Retrofit API,将信息加载到您自己的自定义 DataSource 对象中。
仅限数据库
设置您的 RecyclerView 以观察本地存储空间,最好使用 Room 持久性库。这样,无论您何时在应用数据库中插入或修改数据,这些更改都会自动反映在显示这些数据的 RecyclerView 中。
网络和数据库
在开始观察数据库之后,您可以使用 PagedList.BoundaryCallback 监听数据库中的数据何时耗尽。然后,您可以从网络中获取更多项并将它们插入到数据库中。如果界面正在观察数据库,您只需执行此操作即可。
处理网络连接错误
使用网络对使用 Paging 库显示的数据进行抓取或分页时,切记不要始终将网络视为“可用”或“不可用”,因为许多连接会断断续续或不稳定:
- 特定服务器可能无法响应网络请求。
- 设备可能连接到速度较慢或信号较弱的网络。
您的应用应检查每个请求是否失败,并在网络不可用的情况下尽可能正常恢复。例如,如果数据刷新步骤不起作用,您可以提供“重试”按钮供用户选择。如果在数据分页步骤中发生错误,最好自动重新尝试分页请求。
更新现有应用
如果您的应用已经耗尽了数据库或后端来源中的数据,则可以直接升级到 Paging 库提供的功能。本部分介绍如何升级采用现有通用设计的应用。
自定义分页解决方案
如果您使用自定义功能从应用的数据源加载较小的数据子集,则可以将此逻辑替换为 PagedList 类中的逻辑。PagedList 实例提供了与常见数据源的内置连接。这些实例还为应用界面中可能包含的 RecyclerView 对象提供了适配器。
使用列表而不是页面加载的数据
如果您使用内存中列表作为界面适配器的后备数据结构,并且列表中的项数量可能会变得非常大,请考虑使用 PagedList 类观察数据更新。PagedList 实例可以使用 LiveData<PagedList> 或 Observable<List> 向您的应用界面传递数据更新,从而最大限度地缩短加载时间并减少内存用量。在应用中将 List 对象替换成 PagedList 对象不需要对应用界面结构或数据更新逻辑进行任何更改,就可以获得更理想的结果。
使用 CursorAdapter 将数据游标与列表视图相关联
您的应用可能会使用 CursorAdapter 将 Cursor 的数据与 ListView 相关联。在这种情况下,您通常需要从 ListView 迁移到 RecyclerView,以后者作为应用的列表界面容器,然后将 Cursor 组件替换为 Room 或 PositionalDataSource,具体取决于 Cursor 实例是否会访问 SQLite 数据库。
在某些情况下,例如在使用 Spinner 的实例时,您只需提供适配器本身。然后,库将获取加载到该适配器中的数据,并为您显示这些数据。在这类情况下,请将适配器的数据类型更改为 LiveData<PagedList>,然后将此列表封装到