在项目中,当需要对在线数据和本地数据进行混合分页处理时,Paging3 提供了强大的工具,能够帮助我们优雅地实现数据加载和切换逻辑。然而,对于一些复杂的场景,例如在线数据与本地数据的动态切换,或者在没有在线数据时优雅降级到本地数据,这些仍然需要我们做一些额外的处理和优化。
我们的项目需要实现一个复杂的分页逻辑:
1. 实现
PagingSource
PagingSource 是 Paging3 的核心组件,用于处理分页加载逻辑。我们需要实现一个通用的数据源,在加载在线数据失败时切换到本地数据源。
2. 在线与本地数据切换逻辑
在
PagingSource 中,数据请求失败时,查询本地数据并返回。
3. 数据源切换
当用户刷新或需要重新加载数据时,动态切换在线和本地数据源。
以下是具体代码实现示例:
class ListPagingSource(private val token: String) : PagingSource<Int, Record>() {
private val mRecordDao by lazy { AppDataBase.getInstance().getRecordDao() }
override fun getRefreshKey(state: PagingState<Int, Record>): Int? {
// 定义刷新关键点
return null
}
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Record> {
return try {
if (token.isEmpty()) {
throw IllegalArgumentException("Token 不能为空")
}
val page = params.key ?: FIRST_PAGE_INDEX
val response = Service.getPage(token, page) // 请求在线数据
val responseData = response.data
if (response.isSuccess && responseData != null) {
// 返回在线数据
LoadResult.Page(
data = responseData.records,
prevKey = if (page > FIRST_PAGE_INDEX) page - 1 else null,
nextKey = if (page < responseData.totalPage) page + 1 else null
)
} else {
// 切换到本地数据
val localData = mRecordDao.getAllRecord()
LoadResult.Page(data = localData, prevKey = null, nextKey = null)
}
} catch (e: Exception) {
// 错误处理
LoadResult.Error(e)
}
}
companion object {
private const val FIRST_PAGE_INDEX = 1
}
}
如果本地数据量较小或者业务场景不复杂,可以不对本地数据进行分页处理,而是直接在加载在线数据失败时展示全部本地数据。此方案实现简单,适合轻量级场景,但当数据量较大时,用户体验可能会受到影响。
实现示例:
if (response.isSuccess) {
// 展示在线数据
LoadResult.Page(data = responseData.records, prevKey = prevKey, nextKey = nextKey)
} else {
// 加载全部本地数据
val localData = mRecordDao.getAllRecord()
LoadResult.Page(data = localData, prevKey = null, nextKey = null)
}
优点:实现简单,适合数据量较小的场景。
缺点:数据量大时,加载速度较慢且可能引发性能问题。
为了提升大数据量场景下的用户体验,我们可以对本地数据和在线数据分别进行分页处理。以下是方案步骤:
PagingSource。
实现独立的本地数据
PagingSource
fun getLocalPagedData(): Flow<PagingData<Record>> {
return Pager(
config = PagingConfig(
pageSize = 30,
enablePlaceholders = false
),
pagingSourceFactory = { dao.getPagedRecords() }
).flow.cachedIn(viewModelScope)
}
切换数据源时避免崩溃
Paging3 在加载数据时直接切换数据源会导致
IndexOutOfBoundsException,解决方法是在切换数据源前先提交一个空的
PagingData。
cloudPageAdapter.submitData(PagingData.empty()) // 提交空数据 cloudPageAdapter.submitData(newPagingData) // 提交新数据源
进一步优化:处理用户点击事件崩溃
如果用户在空数据加载时触发点击事件,也可能导致崩溃。通过延迟加载新数据,可以有效避免这一问题:
launch(Dispatchers.IO) {
cloudPageAdapter.submitData(PagingData.empty())
delay(100) // 延迟 100 毫秒
cloudPageAdapter.submitData(newPagingData)
}
Paging3 提供了强大的分页加载能力,但在复杂的场景中,例如在线与本地数据切换时,仍需要我们精心设计和优化。以下是关键点:
本文同步发表在我的公众号“ 柿蒂”上,欢迎大家订阅关注
https://mp.weixin.qq.com/s/nYINi-t_FKIYe-UZDXQMHQ
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69917874/viewspace-3056780/ ,如需转载,请注明出处,否则将追究法律责任。