MVP架构下使用Paging3与RxJava遇数据加载异常问题
问题根源与解决方案
核心问题
你代码里使用了RxJava的subscribe方法,这是异步非阻塞的调用——调用后代码会立刻继续执行responseData.addAll(data),但此时网络请求还在后台处理,data还没被赋值(甚至会因为lateinit未初始化触发异常)。而你看到的日志是网络请求完成后才打印的,这就造成了「日志有数据但RecyclerView为空」的矛盾。
修复方案
在PagingSource的suspend函数中,必须等待RxJava异步任务完成后再返回结果。可以通过RxJava与协程的适配扩展来实现,步骤如下:
- 先确保引入协程-RxJava适配依赖(以Rx3为例):
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-rx3:1.7.3"
- 修改
RepoPagingSource代码:
class RepoPagingSource @Inject constructor( private val repository: ApiRepository, val context: Context ) : PagingSource<Int, RepositoryResponse>() { private lateinit var sharedPref: SharedPref override suspend fun load(params: LoadParams<Int>): LoadResult<Int, RepositoryResponse> { sharedPref = SharedPref(context) return try { val currentPage = params.key ?: 1 // 用await()让协程等待RxJava请求完成,同步获取响应 val response = repository .getRepositories("bearer ${sharedPref.accessToken}", currentPage) .applyIoScheduler() .await() val responseCode = response.code().toString() // 处理body为空的情况,避免空指针 val data = response.body() ?: mutableListOf() Log.d("RepoPagingSource", responseCode) Log.d("RepoPagingSource", data.size.toString()) Log.d("RepoPagingSource", data.toString()) LoadResult.Page( data = data, // 修正prevKey:上一页应为currentPage-1,而非固定-1 prevKey = if (currentPage == 1) null else currentPage - 1, // 当返回数据为空时,停止加载下一页 nextKey = if (data.isEmpty()) null else currentPage + 1 ) } catch (e: Exception) { LoadResult.Error(e) } } override fun getRefreshKey(state: PagingState<Int, RepositoryResponse>): Int? { // 优化refreshKey逻辑,让Paging在刷新时能定位到当前页面附近 return state.anchorPosition?.let { anchorPosition -> state.closestPageToPosition(anchorPosition)?.prevKey ?: state.closestPageToPosition(anchorPosition)?.nextKey } } }
额外修正说明
- 移除了不必要的
lateinit变量,避免未初始化的风险; - 修正了
prevKey的错误逻辑(之前固定为-1会导致Paging无法正确加载上一页); - 添加了
nextKey的空数据判断,避免无效的下一页请求; - 处理了
response.body()为空的场景,防止空指针异常。
内容的提问来源于stack exchange,提问作者Rey
相关产品推荐
相关产品推荐

