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

Jetpack Compose重组引发API重复调用问题求助

解决Composable重组导致分页API重复调用的问题

问题根源

你在Composable的顶层代码中直接调用mViewModel.fetchCompletedTodos(),而Composable会因状态变化频繁重组,每次重组都会执行这个方法。如果fetchCompletedTodos()每次调用都会创建新的分页Flow(比如重新实例化PagingSource或发起新的API请求),就会导致API被反复调用。

解决方案

1. 在ViewModel中缓存分页Flow

将分页Flow的创建逻辑放在ViewModel中,并只初始化一次,确保每次获取的都是同一个Flow实例:

class TodosViewModel : ViewModel() {
    // 缓存分页Flow,仅在ViewModel初始化时创建一次
    val completedTodosFlow: Flow<PagingData<Todo>> = Pager(
        config = PagingConfig(pageSize = 20), // 根据需求调整分页配置
        pagingSourceFactory = { TodoPagingSource(apiService) } // 你的PagingSource实现
    ).flow
}

如果你的fetchCompletedTodos()有复杂业务逻辑,可以封装成私有方法,但要保证只返回同一个Flow实例:

class TodosViewModel : ViewModel() {
    val completedTodosFlow = fetchCompletedTodos()

    private fun fetchCompletedTodos(): Flow<PagingData<Todo>> {
        // 这里可以添加你的业务逻辑,比如参数处理
        return Pager(
            config = PagingConfig(pageSize = 20),
            pagingSourceFactory = { TodoPagingSource(apiService) }
        ).flow
    }
}

2. 修改Composable代码

在Composable中直接使用ViewModel中缓存好的Flow,避免每次重组都触发新的Flow创建:

composable(HomeSections.Todo.route) { from ->
    val mViewModel: TodosViewModel = hiltViewModel()
    val uiState = mViewModel.uiState.collectAsState()

    Timber.i("Recomposition Logs >> HomeSections.Todo.route")

    // 使用ViewModel中缓存的Flow,不再每次调用fetchCompletedTodos()
    val completedTodos = mViewModel.completedTodosFlow.collectAsLazyPagingItems()
}

核心原则

Composable的重组是频繁且不可控的,所有产生副作用(如API调用、数据更新)的逻辑都不应该直接放在Composable顶层代码中,必须放到ViewModel(用于持有状态和业务逻辑)或副作用处理函数(如LaunchedEffect、rememberCoroutineScope)中,确保操作只执行必要的次数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 09:40:13