Jetpack Compose进度条每秒更新时出现异常行为问题
问题原因
在Composable内部直接创建Handler并post Runnable的核心问题是:每次progress更新触发Composable重组时,都会重新生成新的Handler和Runnable实例,并且重复post任务。最终导致多个Runnable同时在主线程队列中执行,每秒会多次执行progress +=0.01f,进度增速自然远超预期。
而普通float变量的逻辑不在Composable上下文内,不会触发重组,因此始终只有一个Runnable循环执行,速度符合设定。
解决方法
方法1:使用LaunchedEffect(推荐)
LaunchedEffect是Compose专为协程异步任务设计的API,它会在Composable首次进入组合时启动协程,仅在指定key变化时才重启,从根源避免重复创建任务。
var progress by remember { mutableStateOf(0.00f) } val animatedProgress by animateFloatAsState( targetValue = progress, animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec ) // 传入Unit作为key,确保仅在首次组合时启动协程 LaunchedEffect(Unit) { // 可添加终止条件,比如进度到100%时停止 while (progress < 1.0f) { delay(1000) progress += 0.01f println(progress) } } LinearProgressIndicator(progress = animatedProgress)
方法2:用remember保留Handler和Runnable实例
通过remember让Handler和Runnable在重组时保持唯一实例,避免重复post任务:
var progress by remember { mutableStateOf(0.00f) } val animatedProgress by animateFloatAsState( targetValue = progress, animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec ) // 用remember保存Handler,重组时复用同一个实例 val mainHandler = remember { Handler(Looper.getMainLooper()) } // 用remember保存Runnable,确保不会重复创建 val updateRunnable = remember { object : Runnable { override fun run() { if (progress >= 1.0f) { mainHandler.removeCallbacks(this) return } progress += 0.01f println(progress) mainHandler.postDelayed(this, 1000) } } } // 用LaunchedEffect触发首次任务,避免重组时重复post LaunchedEffect(Unit) { mainHandler.post(updateRunnable) } LinearProgressIndicator(progress = animatedProgress)
内容的提问来源于stack exchange,提问作者Pisoj
相关产品推荐
相关产品推荐

