You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose配合Paging3时RemoteMediator错误如何传递到ViewModel

你当前的写法无法捕获错误核心原因是:fetchPeople()方法仅构造并返回Pager的Flow对象,不会立刻执行网络请求,实际加载逻辑是在PagingData被订阅时才触发的,所以你在ViewModel的init块里加的try-catch只能捕获构造Flow过程中出现的异常,完全接触不到RemoteMediator加载时抛出的错误。

以下是两种常用的实现方案:

方案1:通过Paging3原生加载状态监听处理(推荐)

Paging3本身提供了加载状态回调,包含了refresh、prepend、append三个阶段的状态,RemoteMediator返回的错误会自动封装到加载状态里,你可以直接在UI层或者ViewModel层监听处理。

调整ViewModel代码

@ExperimentalPagingApi
@HiltViewModel
class PeopleViewModel @Inject constructor(private val repo: PeopleRepository) : ViewModel() {
    // 直接返回PagingData Flow,用cachedIn做页面重建缓存
    val peopleFlow = repo.fetchPeople()
        .cachedIn(viewModelScope)
}

Compose层收集并处理错误

val lazyPagingItems = viewModel.peopleFlow.collectAsLazyPagingItems()

when {
    // 处理首次刷新/下拉刷新的错误
    lazyPagingItems.loadState.refresh is LoadState.Error -> {
        val error = (lazyPagingItems.loadState.refresh as LoadState.Error).error
        // 展示错误UI,比如错误页、吐司提示
        Text(text = error.message ?: "数据加载失败")
    }
    // 处理加载中状态
    lazyPagingItems.loadState.refresh is LoadState.Loading -> {
        CircularProgressIndicator()
    }
    else -> {
        LazyColumn {
            items(lazyPagingItems) { character ->
                // 渲染列表项
            }
            // 处理加载更多的错误和状态
            lazyPagingItems.loadState.append.apply {
                when(this) {
                    is LoadState.Loading -> item { CircularProgressIndicator() }
                    is LoadState.Error -> item { Text("加载更多失败:${error.message}") }
                    else -> {}
                }
            }
        }
    }
}

方案2:ViewModel层统一接收错误

如果你需要把错误统一收拢到ViewModel处理,可以通过事件流传递RemoteMediator捕获的错误。

1. 新增全局错误事件流

在Hilt模块中提供单例的错误事件流:

@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    @Provides
    fun provideErrorEventFlow(): MutableSharedFlow<Throwable> {
        return MutableSharedFlow(extraBufferCapacity = 1)
    }
}

2. 修改RemoteMediator发送错误

@ExperimentalPagingApi
class PeopleRemoteMediator @Inject constructor(
    private val database: AppDatabase,
    private val service: PeopleService,
    private val errorFlow: MutableSharedFlow<Throwable>
) : RemoteMediator<Int, SWCharacter>() {
    // 省略其他不变的代码
    override suspend fun load(loadType: LoadType, state: PagingState<Int, SWCharacter>): MediatorResult {
        return try {
            // 省略原有请求逻辑
        } catch (e: IOException) {
            errorFlow.emit(e)
            MediatorResult.Error(e)
        } catch (e: ResponseException) {
            errorFlow.emit(e)
            MediatorResult.Error(e)
        }
    }
}

3. 调整Repository暴露错误流

class PeopleRepository @Inject constructor(
    private val database: AppDatabase,
    private val service: PeopleService,
    private val errorFlow: MutableSharedFlow<Throwable>
) {
    val globalErrorFlow: Flow<Throwable> = errorFlow

    @ExperimentalPagingApi
    fun fetchPeople(): Flow<PagingData<SWCharacter>> {
        return Pager(
            PagingConfig(pageSize = 10, enablePlaceholders = false, prefetchDistance = 3),
            remoteMediator = PeopleRemoteMediator(database, service, errorFlow),
            pagingSourceFactory = { database.people().pagingSource() }
        ).flow
    }
}

4. ViewModel收集错误更新UI

@ExperimentalPagingApi
@HiltViewModel
class PeopleViewModel @Inject constructor(private val repo: PeopleRepository) : ViewModel() {
    private val _uiState = mutableStateOf<UIState>(UIState.Loading)
    val uiState: State<UIState> = _uiState

    val peopleFlow = repo.fetchPeople().cachedIn(viewModelScope)

    init {
        // 收集错误事件更新UI状态
        viewModelScope.launch {
            repo.globalErrorFlow.collect { e ->
                _uiState.value = UIState.Error(message = e.message ?: "加载失败")
            }
        }
        // 数据加载成功更新UI状态
        viewModelScope.launch {
            peopleFlow.collectLatest {
                _uiState.value = UIState.Success(data = it)
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Valerio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 05:57:04