如何正确设置LinearProgressIndicator状态?实现手动触发进度任务
解决方案
问题出在你原本的progress Flow是在ViewModel初始化时就通过stateIn自动启动订阅了,只要Composable一收集这个StateFlow,Flow里的循环任务就会立刻执行。要改成用户手动触发,需要把任务的执行逻辑和Flow的订阅解耦,让任务只在用户操作时才启动。
修改后的ViewModel代码
@HiltViewModel class HomeViewModel @Inject constructor(private val hotHubRepository: HotHubRepository): ViewModel(){ // 用MutableStateFlow保存进度,初始值0 private val _progress = MutableStateFlow(0) val progress = _progress.asStateFlow() // 标记任务是否正在运行,防止重复触发 private val _isTaskRunning = MutableStateFlow(false) val isTaskRunning = _isTaskRunning.asStateFlow() // 用户触发任务的函数 fun startProgressTask() { // 如果任务正在运行,直接返回,避免重复执行 if (_isTaskRunning.value) return viewModelScope.launch { _isTaskRunning.value = true try { for(i in 0 .. 1000){ // 模拟耗时网络请求 delay(200) _progress.value = i } } finally { // 任务结束后重置运行状态 _isTaskRunning.value = false } } } }
修改后的HomeScreen代码
@Composable fun HomeScreen(navController: NavHostController) { val viewModel = hiltViewModel<HomeViewModel>() val progress by viewModel.progress.collectAsStateWithLifecycle() val isTaskRunning by viewModel.isTaskRunning.collectAsStateWithLifecycle() Column( modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp) ) { Text(text = "当前进度: $progress") // 手动触发任务的按钮,任务运行时置灰不可点击 Button( onClick = { viewModel.startProgressTask() }, enabled = !isTaskRunning ) { Text(if (isTaskRunning) "任务执行中" else "开始进度任务") } // 你的LinearProgressIndicator LinearProgressIndicator(progress = progress / 1000f) } }
关键修改点说明
- 用
MutableStateFlow替代原来自动启动的Flow:进度的发射不再是Flow初始化时自动执行,而是在startProgressTask函数里手动启动协程来完成 - 增加
isTaskRunning状态:避免用户重复点击按钮触发多个并行任务,同时可以给按钮做状态切换(比如运行时置灰) - 任务逻辑包裹在
viewModelScope的协程里:确保ViewModel销毁时任务自动取消,不会出现内存泄漏
内容的提问来源于stack exchange,提问作者SageJustus
相关产品推荐
相关产品推荐

