如何将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,提问作者Владислава Черкасова
相关产品推荐
相关产品推荐

