You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin RecyclerView点击选项后无法即时更新背景的问题

问题描述

我是Kotlin新手,若发现代码存在问题或不良实践,欢迎指出。当前我开发了一款答题类小应用,用户需从多个选项中选择正确答案:选中正确答案时,选项需高亮绿色250毫秒后进入下一题;选中错误答案则直接标记错误。切换下一题的逻辑在主Activity中实现,背景更改逻辑在Adapter类中编写,相关Adapter代码如下:

class QuestionOptionAdapter(
    private val items: ArrayList<String>,
    private val correctAnswer: String,
) : RecyclerView.Adapter<QuestionOptionAdapter.ViewHolder>() {

    var onSelectedAnswer: (String) -> Unit = {}
    var onSelectedCorrectAnswer: () -> Unit = {}
    var onSelectedIncorrectAnswer: () -> Unit = {}

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val item = items[position]
        holder.tvOption.text = item
        holder.tvOption.setOnClickListener {
            if (item == correctAnswer) {
                runBlocking {
                    it.background =
                        ContextCompat.getDrawable(it.context, R.drawable.question_opt_correct)

                    delay(250)
                }
                onSelectedCorrectAnswer()


            } else {
                it.background =
                    ContextCompat.getDrawable(it.context, R.drawable.question_opt_incorrect)

                onSelectedIncorrectAnswer()
            }
        }
    }
}

我发现,虽然更改背景的代码在onSelectedCorrectAnswer()之前执行,但背景要等到整个代码块执行完毕才会更新,导致用户看不到高亮效果。请问如何让背景更新在代码块结束前显示?


问题原因

你使用runBlocking执行延迟操作时,会直接阻塞主线程。Android的UI更新任务是在主线程队列中排队执行的,设置背景后立刻用runBlocking卡住主线程,UI刷新任务会被积压,直到delay(250)执行完毕、主线程恢复后才能显示,所以用户看不到高亮效果。


解决方案

不要用runBlocking,改用非阻塞的方式实现延迟,让主线程能立刻处理UI更新:

方案1:使用协程(推荐)

借助AndroidX的lifecycleScope(绑定生命周期,避免内存泄漏)启动协程,延迟操作不会阻塞主线程:

// 确保build.gradle中添加依赖
// implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.6.2"

class QuestionOptionAdapter(
    private val items: List<String>, // 改用不可变List更规范
    private val correctAnswer: String,
    private val lifecycleScope: LifecycleScope // 从Activity/Fragment传入绑定生命周期的Scope
) : RecyclerView.Adapter<QuestionOptionAdapter.ViewHolder>() {

    var onSelectedCorrectAnswer: () -> Unit = {}
    var onSelectedIncorrectAnswer: () -> Unit = {}

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val item = items[position]
        holder.tvOption.text = item
        holder.tvOption.setOnClickListener { view ->
            // 立刻更新背景
            view.background = ContextCompat.getDrawable(view.context, R.drawable.question_opt_correct)
            // 禁用点击防止重复触发
            view.isClickable = false
            
            lifecycleScope.launch {
                delay(250)
                onSelectedCorrectAnswer()
            }
        } else {
            view.background = ContextCompat.getDrawable(view.context, R.drawable.question_opt_incorrect)
            view.isClickable = false
            onSelectedIncorrectAnswer()
        }
    }

    // ViewHolder实现省略...
}

在Activity/Fragment中初始化Adapter时传入lifecycleScope:

val adapter = QuestionOptionAdapter(items, correctAnswer, lifecycleScope)

方案2:使用Handler.postDelayed

如果不想引入协程依赖,也可以用传统的Handler实现延迟:

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    val item = items[position]
    holder.tvOption.text = item
    holder.tvOption.setOnClickListener { view ->
        if (item == correctAnswer) {
            view.background = ContextCompat.getDrawable(view.context, R.drawable.question_opt_correct)
            view.isClickable = false
            
            Handler(Looper.getMainLooper()).postDelayed({
                onSelectedCorrectAnswer()
            }, 250)
        } else {
            view.background = ContextCompat.getDrawable(view.context, R.drawable.question_opt_incorrect)
            view.isClickable = false
            onSelectedIncorrectAnswer()
        }
    }
}

额外优化建议
  • 切换题目时,记得恢复所有选项的点击状态和默认背景,避免下一题选项异常。
  • 提前初始化Drawable资源(比如在Adapter构造方法中加载),避免每次点击都重复调用ContextCompat.getDrawable,提升性能。
  • 用List<String>替代ArrayList<String>作为参数,符合不可变数据的设计原则。

内容的提问来源于stack exchange,提问作者Salaah Amin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 01:05:23