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

如何将Todo列表从TodoAdapter传递给BottomSheetDialog?

问题解决:BottomSheet添加Todo并更新RecyclerView

你不需要用Intent传递列表,正确的做法是让Activity统一管理Todo数据,通过接口回调让BottomSheet把新创建的Todo传给Activity,再由Activity更新Adapter和RecyclerView。以下是具体修改步骤:


1. 重构数据管理,将Todo列表移到MainActivity

把原来放在Adapter里的MutableList移到MainActivity,让Activity作为数据的统一管理者,Adapter只负责展示数据:

修改MainActivity.kt:

package com.bignerdranch.android.taskmaster

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.recyclerview.widget.LinearLayoutManager
import com.bignerdranch.android.taskmaster.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity(), NewTaskSheet.OnTodoSavedListener {

    private lateinit var todoAdapter: TodoAdapter
    private lateinit var binding: ActivityMainBinding
    // 把Todo列表移到Activity中管理
    private val todoList = mutableListOf<Todo>()

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

        todoAdapter = TodoAdapter(todoList)
        binding.rvTodoItems.adapter = todoAdapter
        binding.rvTodoItems.layoutManager = LinearLayoutManager(this)
        
        binding.btnAddTodo.setOnClickListener{
            NewTaskSheet().apply {
                setOnTodoSavedListener(this@MainActivity)
            }.show(supportFragmentManager,"NewTaskTag")
        }
    }

    // 实现回调接口,接收新的Todo并更新列表
    override fun onTodoSaved(newTodo: Todo) {
        todoList.add(newTodo)
        todoAdapter.notifyItemInserted(todoList.size - 1)
    }
}

2. 给NewTaskSheet添加回调接口,传递新创建的Todo

修改NewTaskSheet.kt,添加接口用于通知Activity保存了新Todo:

package com.bignerdranch.android.taskmaster

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.bignerdranch.android.taskmaster.databinding.FragmentNewTaskSheetBinding
import com.google.android.material.bottomsheet.BottomSheetDialogFragment

class NewTaskSheet : BottomSheetDialogFragment(){

    private lateinit var binding: FragmentNewTaskSheetBinding
    private var listener: OnTodoSavedListener? = null

    // 定义回调接口
    interface OnTodoSavedListener {
        fun onTodoSaved(newTodo: Todo)
    }

    fun setOnTodoSavedListener(listener: OnTodoSavedListener) {
        this.listener = listener
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentNewTaskSheetBinding.inflate(inflater,container,false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        binding.btnSave.setOnClickListener {
            val title = binding.title.text.toString().trim()
            val description = binding.description.text.toString().trim()
            // 创建新的Todo对象
            val newTodo = Todo(title, description)
            // 通知Activity保存
            listener?.onTodoSaved(newTodo)
            // 关闭BottomSheet
            dismiss()
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        listener = null // 避免内存泄漏
    }
}

3. 修复TodoAdapter中的错误

原来的Adapter存在两处问题:onCreateViewHolder里重复return,以及CheckBox的状态监听和点击监听冲突,以下是修复后的代码:

package com.bignerdranch.android.taskmaster

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

class TodoAdapter(
    val todos: MutableList<Todo>
): RecyclerView.Adapter<TodoAdapter.TodoViewHolder>() {

    class TodoViewHolder(val binding: ItemTodoBinding): RecyclerView.ViewHolder(binding.root)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder {
        val binding = ItemTodoBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return TodoViewHolder(binding)
    }

    private fun toggleStrikeThrough(tvTodoTitle: android.widget.TextView, isChecked: Boolean){
        if(isChecked){
            tvTodoTitle.paintFlags = tvTodoTitle.paintFlags or STRIKE_THRU_TEXT_FLAG
        }else{
            tvTodoTitle.paintFlags = tvTodoTitle.paintFlags and STRIKE_THRU_TEXT_FLAG.inv()
        }
    }

    override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
        val curTodo = todos[position]
        holder.binding.apply {
            tvTodoTitle.text = curTodo.title
            cbDone.isChecked = curTodo.isChecked
            toggleStrikeThrough(tvTodoTitle, curTodo.isChecked)
            
            // 只保留状态改变监听,移除重复的点击监听
            cbDone.setOnCheckedChangeListener { _, isChecked ->
                toggleStrikeThrough(tvTodoTitle, isChecked)
                curTodo.isChecked = isChecked
                // 如果需要删除已完成的Todo,建议在这里处理并调用notifyItemRemoved
                // 示例:
                // if(isChecked) {
                //     todos.removeAt(holder.adapterPosition)
                //     notifyItemRemoved(holder.adapterPosition)
                // }
            }
        }
    }

    override fun getItemCount(): Int {
        return todos.size
    }
}

4. 额外说明

  • 不需要传递整个Todo列表给BottomSheet,它只需要创建新的Todo对象
  • 使用notifyItemInserted代替notifyDataSetChanged,性能更优且自带插入动画
  • 优化了Adapter中ViewBinding的使用方式,避免重复调用findViewById

内容的提问来源于stack exchange,提问作者Владислава Черкасова

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 02:22:35