Kotlin协程Flow收集电影数据重复累加问题咨询
问题结论
不需要把ViewModel调用逻辑移到Activity中,数据重复累加的问题和调用位置无关,完全是现有代码的状态管理、数据收集逻辑写错导致的。
问题根源
- 核心错误在ViewModel的收集逻辑:每次Flow每隔5秒返回新的全量电影列表时,你调用
addAll()往原有列表里追加数据,还把清空列表的代码注释掉了,自然首次3条、第二次追加3条变6条、第三次变9条。 - 现有状态管理不符合Compose规范:你直接对外暴露可变
MutableList,列表内部元素变化不会触发Compose重组,后续做收藏、详情交互时会出现UI不更新的问题。 - Repo层的Flow存在泄漏风险:用
while(true)无限循环没有判断协程活跃状态,页面销毁、协程取消时循环不会自动停止,还没有加网络异常兜底。
修正后的实现代码
1. Repo层修正
// 不需要给方法加suspend修饰,flow构建器本身是非阻塞的 override fun getPopularMovies() : Flow<List<Movie>> = flow{ // 用isActive替换while(true),协程取消时自动退出循环,避免资源泄漏 while(currentCoroutineContext().isActive){ try { val latestMovies = movieApi.getPopularMovies() emit(latestMovies) } catch (e: Exception) { // 自行处理网络请求异常,比如打日志、兜底错误状态 Log.e("MovieRepo", "获取热门电影失败", e) } delay(5000) } }
2. ViewModel层修正
class HomeViewModel(private val repository: MovieRepo): ViewModel() { // 内部用可变StateFlow持有状态,初始值为空列表 private val _popularMovies = MutableStateFlow<List<Movie>>(emptyList()) // 对外暴露不可变StateFlow,禁止UI层直接修改数据 val popularMovies: StateFlow<List<Movie>> = _popularMovies.asStateFlow() init{ viewModelScope.launch { repository.getPopularMovies().collect{ newMovieList -> // 每次拿到新的全量列表直接替换旧数据,不要addAll追加 _popularMovies.value = newMovieList } } } // 后续交互逻辑都放在ViewModel里,比如切换收藏状态 fun toggleFavorite(movieId: Int) { // 在这里处理收藏状态修改,更新_stateFlow的值即可 } }
注意:不需要给协程指定
Dispatchers.Default,Retrofit的网络请求本身会自动切换IO线程,Flow收集不会阻塞主线程。
3. Compose页面修正
@Composable fun HomeScreen() { val viewModel = getViewModel<HomeViewModel>() // 用生命周期感知的方式收集Flow,页面不可见时自动停止收集,节省资源 val popularMovies by viewModel.popularMovies.collectAsStateWithLifecycle() // 这里拿到的popularMovies是不可变列表,直接传给子组件即可 // 交互事件通过传方法的方式回调给ViewModel,不要把可变列表传给子组件 // MovieList( // movies = popularMovies, // onMovieClick = { movie -> /* 跳转详情逻辑 */ }, // onFavoriteClick = { movieId -> viewModel.toggleFavorite(movieId) } // ) }
补充说明
通过getViewModel()在Composable中获取的ViewModel,和在Activity中获取的是同作用域的同一个实例,不存在调用位置导致的数据异常问题。后续做交互时遵循「状态向下传递、事件向上回调」的Compose状态管理原则即可,不要把可变集合直接暴露给UI层,所有数据修改逻辑收敛到ViewModel中,就不会出现数据错乱、UI不刷新的问题。
内容的提问来源于stack exchange,提问作者Equlo
相关产品推荐
相关产品推荐

