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

Android Kotlin应用View Binding异常:待办任务标题及删除功能故障求助

待办应用View Binding重构问题修复

问题现象

  • 新增任务时,自定义输入的标题不显示,始终展示默认的“Example”文本
  • 删除已完成任务的功能完全失效

错误分析与修复方案

核心错误点

  1. Adapter全局复用单个Binding实例:在ToDoAdapter中声明了全局的ItemTodoBinding,导致所有列表项共用同一个绑定对象,无法正确渲染每个任务的自定义标题。
  2. ViewHolder未绑定ItemTodoBinding:原ViewHolder仅持有View对象,没有关联对应的Binding,无法在onBindViewHolder中正确操作每个列表项的视图。
  3. 复选框状态更新逻辑错误:复选框状态变更时,任务的isChecked值被错误反转,导致删除功能无法正确识别已完成的任务。

修正后的代码

MainActivity.kt(优化Adapter初始化)

package com.example.todo

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.todo.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    private lateinit var toDoAdapter: ToDoAdapter
    private lateinit var binding: ActivityMainBinding

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

        // 无需传递layoutInflater给Adapter,ViewHolder中自行处理
        toDoAdapter = ToDoAdapter(mutableListOf())
        binding.RVToDoItems.adapter = toDoAdapter
        binding.RVToDoItems.layoutManager = LinearLayoutManager(this)

        binding.BTNAddToDo.setOnClickListener {
            val toDoTitle = binding.ETToDoTitle.text.toString()
            if (toDoTitle.isNotEmpty()) {
                val todo = ToDo(toDoTitle)
                toDoAdapter.addToDo(todo)
                binding.ETToDoTitle.text.clear()
            }
        }

        binding.BTNDeleteDoneToDos.setOnClickListener {
            toDoAdapter.deleteDoneToDos()
        }
    }
}

ToDoAdapter.kt(核心修复)

package com.example.todo

import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.todo.databinding.ItemTodoBinding

class ToDoAdapter(
    private val todos: MutableList<ToDo>
) : RecyclerView.Adapter<ToDoAdapter.ToDoViewHolder>() {

    // 修改ViewHolder,持有ItemTodoBinding实例
    class ToDoViewHolder(val binding: ItemTodoBinding) : RecyclerView.ViewHolder(binding.root)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ToDoViewHolder {
        // 在ViewHolder创建时,为每个项单独初始化Binding
        val binding = ItemTodoBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return ToDoViewHolder(binding)
    }

    fun addToDo(todo: ToDo) {
        todos.add(todo)
        notifyItemInserted(todos.size - 1)
    }

    fun deleteDoneToDos() {
        todos.removeAll { todo -> todo.isChecked }
        notifyDataSetChanged()
    }

    private fun toggleStrikeThrough(titleView: androidx.appcompat.widget.AppCompatTextView, isChecked: Boolean) {
        if (isChecked) {
            titleView.paintFlags = titleView.paintFlags or STRIKE_THRU_TEXT_FLAG
        } else {
            titleView.paintFlags = titleView.paintFlags and STRIKE_THRU_TEXT_FLAG.inv()
        }
    }

    override fun getItemCount(): Int = todos.size

    override fun onBindViewHolder(holder: ToDoViewHolder, position: Int) {
        val currTodo = todos[position]
        // 使用当前ViewHolder持有的Binding操作视图
        holder.binding.apply {
            TVToDoTitle.text = currTodo.title
            CBDone.isChecked = currTodo.isChecked
            toggleStrikeThrough(TVToDoTitle, currTodo.isChecked)

            CBDone.setOnCheckedChangeListener { _, isChecked ->
                toggleStrikeThrough(TVToDoTitle, isChecked)
                // 修正状态更新逻辑,直接赋值为当前选中状态
                currTodo.isChecked = isChecked
            }
        }
    }
}

ToDo.kt(保留原代码)

package com.example.todo

data class ToDo(
    val title: String,
    var isChecked: Boolean = false
)

修复说明

  1. 移除Adapter全局Binding:每个列表项的Binding在onCreateViewHolder中单独初始化,确保每个项拥有独立的视图绑定对象。
  2. ViewHolder持有Binding:修改ViewHolder结构,使其持有对应的ItemTodoBinding,在onBindViewHolder中通过holder.binding访问当前项的视图。
  3. 修正复选框状态逻辑:将currTodo.isChecked = !currTodo.isChecked改为currTodo.isChecked = isChecked,确保任务的完成状态与复选框选中状态一致,删除功能可正确筛选已完成任务。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 00:27:47