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

Android开发:RecyclerView创建后按钮点击失效及Todo展示问题

问题分析与解决

核心问题

  1. 保存按钮点击后数据已写入数据库,但RecyclerView未刷新,导致你误以为点击事件未触发
  2. 当前Adapter无法动态更新数据,每次获取数据都新建Adapter,既低效又无法复用实例

修复步骤

1. 修改CustomAdapter,支持动态更新数据

给Adapter添加更新数据集的方法,避免重复创建新Adapter:

class CustomAdapter(private var dataSet: List<Todo>) :
    RecyclerView.Adapter<CustomAdapter.ViewHolder>() {

    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val textView: TextView = view.findViewById(R.id.textView3)
    }

    override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(viewGroup.context)
            .inflate(R.layout.recycler_view_row, viewGroup, false)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
        viewHolder.textView.text = dataSet[position].description
    }

    override fun getItemCount() = dataSet.size

    // 添加更新数据的方法
    fun updateData(newData: List<Todo>) {
        dataSet = newData
        notifyDataSetChanged()
    }
}

2. 修改MainActivity,复用Adapter并在保存后刷新数据

将Adapter设为成员变量,保存数据后重新获取最新列表并更新Adapter:

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private lateinit var db: TodoDatabase
    private lateinit var recyclerView: RecyclerView
    // 把Adapter设为成员变量,方便后续更新
    private lateinit var adapter: CustomAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        db = TodoDatabase.getInstance(this)
        setContentView(binding.root)

        val save: Button = binding.button
        val todo: TextInputEditText = binding.todoInput

        // 初始化RecyclerView基础配置,只执行一次
        recyclerView = binding.recyclerView
        recyclerView.layoutManager = LinearLayoutManager(this)
        adapter = CustomAdapter(emptyList())
        recyclerView.adapter = adapter

        // 加载初始数据
        lifecycleScope.launch {
            loadUncheckedTodos()
        }

        save.setOnClickListener {
            val todoText = todo.text.toString()
            if (todoText.isNotEmpty()) {
                lifecycleScope.launch {
                    save(todoText)
                    todo.text?.clear()
                    // 保存完成后重新加载数据并刷新列表
                    loadUncheckedTodos()
                }
            }
        }
    }

    private suspend fun loadUncheckedTodos() {
        val todos = db.todoDao().getUnchecked()
        adapter.updateData(todos)
    }

    private suspend fun save(todo: String) {
        db.todoDao().upsert(Todo(id = null, description = todo, checked = false))
    }
}

3. 关键说明

  • 按钮点击事件实际已触发,只是之前没有刷新RecyclerView导致页面无变化,误以为点击无效
  • Room的suspend方法会自动切换到后台线程执行,无需手动指定Dispatcher,lifecycleScope默认在主线程启动协程,调用suspend方法时会自动切到IO线程,执行完成后回到主线程更新UI,这部分逻辑是安全的
  • 初始化RecyclerView的LayoutManager和Adapter只需要执行一次,避免重复操作影响性能

内容的提问来源于stack exchange,提问作者Dylan Maurits

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 17:05:35