来自网络和数据库的页面
分页库提供了RemoteMediator
组件用于此场景。RemoteMediator
会管理数据从网络加载到本地数据库的过程。
本指南假定您熟悉Room Persistence库和Paging库的基本用法。
基本用法
假设您希望您的应用将User
信息从网络数据源,加载到存储在Room数据库中的本地缓存中。
下图说明了如何RemoteMediator
和 PagingSource
一起工作来满足此场景。
一个RemoteMediator
将来自网络的分页数据加载到数据库中,但不直接将数据加载到UI中。
该应用程序将数据库用作单一可信来源。
换句话说,该应用程序仅显示已缓存在数据库中的数据。一种 PagingSource
实现(例如,由Room生成的实现)负责将缓存的数据从数据库加载到UI中。
创建Room entities
第一步是使用Room持久性库定义一个数据库,该数据库保存来自网络数据源的分页数据的本地缓存。从使用Room将数据保存到本地数据库中RoomDatabase
所述的实现开始。
接下来,定义Room实体,以表示列表项的表,如使用Room实体定义数据中所述 。给它一个id
字段作为主键,并为列表项包含的任何其他信息提供一个字段。
@Entity(tableName = "users")
data class User(val id: String, val label: String)
您还必须按照使用Room DAO访问数据中所述为该Room实体定义数据访问对象(DAO)。列表项实体的DAO必须包含以下方法:
- 一种
insertAll()
将项目列表插入表中的方法。 - 一种查询方法,将查询字符串作为参数,并返回
PagingSource
结果列表的对象。这样,Pager
对象可以将此表用作页面数据的源。 - 一种
clearAll()
删除表中所有数据的方法。
@Dao
interface UserDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAll(users: List<User>)
@Query("SELECT * FROM users WHERE label LIKE :query")
fun pagingSource(query: String): PagingSource<Int, User>
@Query("DELETE FROM users")
suspend fun clearAll()
}
实现RemoteMediator
RemoteMediator
与PagingSource
组件相似。它包含 load()
必须重写以定义加载行为的方法。不同之处在于,对象不是将分页数据从数据源加载到RecyclerView
列表,而是 RemoteMediator
从网络数据源加载分页数据并将其保存到本地数据库。
一个典型的RemoteMediator
实现包括以下参数:
query
:查询字符串,用于定义要从后端服务检索的数据。database
:用作本地缓存的Room数据库。networkService
:后端服务的API实例。
创建一个RemoteMediator<Key, Value>
。该Key
类型和 Value
类型应该是相同的,因为他们将是如果你定义 PagingSource
对同一网络的数据源。有关选择类型参数的更多信息,请参见选择键和值类型。
@OptIn(ExperimentalPagingApi::class)
class ExampleRemoteMediator(
private val query: String,
private val database: RoomDb,
private val networkService: ExampleBackendService
) : RemoteMediator<Int, User>() {
val userDao = database.userDao()
override suspend fun load(
loadType: LoadType,
state: PagingState<Int, User>
): MediatorResult {
// ...
}
}
该load()
方法负责更新支持数据集并初始化PagingSource
。一些支持分页的库(例如Room)将自动处理PagingSource
它们实现的对象。
该load()
方法具有两个参数:
PagingState
,其中包含有关到目前为止加载的页面,最近访问的索引以及PagingConfig
用于初始化分页流的对象的信息。LoadType
,其指示所述负载的类型:REFRESH
,APPEND
,或PREPEND
。
该load()
方法的返回值是一个 MediatorResult
对象。MediatorResult
可以是 MediatorResult.Error
(包括错误说明)或 MediatorResult.Success
(包括表明是否有更多数据要加载的信号)。
该load()
方法必须执行以下步骤:
- 根据加载类型和到目前为止已加载的数据,确定要从网络加载哪个页面。
- 触发网络请求。
- 根据装入操作的结果执行操作:
- 如果加载成功并且收到的项目列表不为空,则将列表项目存储在数据库中并返回
MediatorResult.Success(endOfPaginationReached = false)
。 - 如果加载成功并且收到的项目列表为空,则返回
MediatorResult.Success(endOfPaginationReached = true)
。 - 如果请求导致错误,则返回
MediatorResult.Error
。
- 如果加载成功并且收到的项目列表不为空,则将列表项目存储在数据库中并返回
override suspend fun load(
loadType: LoadType,