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
相关产品推荐
相关产品推荐

