Kotlin Android中Handler postDelayed配合for循环无法依次展示掷骰结果问题
问题根源
- 变量捕获异常:Kotlin循环中的迭代变量
i是所有延迟任务共享的变量,等1000ms后任务执行时,循环已经执行完成,i已经是最后一个索引值,所有Runnable都会读取到同一个最终的i,只会显示最后一个结果。 - 延迟时间设置错误:所有任务都设置了相同的1000ms延迟,所有UI更新任务会在同一时间执行,只能看到最后一次更新的效果。
- 汇总逻辑位置错误:你把汇总结果的更新放在了for循环外面,代码执行时会直接先更新汇总控件,不需要等延迟任务执行。
正确实现方案
Handler实现方案
else if (numTimesRolled.progress <= 3) { val rollCount = numTimesRolled.progress + 1 // 预先生成所有掷骰结果 for (i in 0 until rollCount){ val randNum = Random.nextInt(1, diceIsComfirm) resultsArray[i] = randNum.toString() } // 全局共用同一个Handler,不要每次循环都创建新的Handler实例 val mainHandler = Handler(Looper.getMainLooper()) for (i in 0 until rollCount){ // 把当前索引存到局部变量,解决变量捕获问题 val currentPos = i val updateTask = Runnable { randNumDisplay.text = resultsArray[currentPos] // 最后一个骰子展示完成后再更新汇总结果 if (currentPos == rollCount - 1) { randNumResultsDisplay.text = "Rolled ${resultsArray.joinToString(" ")}" } } // 每个任务的延迟时间递增,间隔可以自行调整,这里设置为每次间隔500ms mainHandler.postDelayed(updateTask, (i + 1) * 500L) } }
协程实现方案(更简洁,Android X环境推荐)
需要先引入kotlin协程Android依赖,代码逻辑更符合直觉,不需要处理变量捕获问题:
else if (numTimesRolled.progress <= 3) { val rollCount = numTimesRolled.progress + 1 lifecycleScope.launch { for (i in 0 until rollCount) { val randNum = Random.nextInt(1, diceIsComfirm) resultsArray[i] = randNum.toString() randNumDisplay.text = resultsArray[i] // 每次掷骰后等待500ms再执行下一次 delay(500L) } // 所有掷骰完成后更新汇总结果 randNumResultsDisplay.text = "Rolled ${resultsArray.joinToString(" ")}" } }
内容的提问来源于stack exchange,提问作者Ray Paxman
相关产品推荐
相关产品推荐

