Kotlin RecyclerView分类项编辑更新数据库功能异常求助
核心问题排查
你的更新失败问题本质是数据库无法定位待修改条目:你点击确认时只将新名称传给了上层,没有携带对应分类的唯一主键(一般是id字段),直接新建无主键的Category对象调用更新方法,数据库找不到匹配条目自然不会执行更新操作。
除此之外原有代码还有性能冗余、编辑状态滚动丢失、重复绑定监听等问题,以下是优化后的完整实现:
优化代码实现
1. CategoryAdapter 改造
class CategoryAdapter( private var categoryList: MutableList<Category> = mutableListOf(), val listener: ClickListener ) : RecyclerView.Adapter<CategoryAdapter.MyViewHolder>() { // 记录当前正在编辑的条目位置,解决滚动后编辑状态丢失问题 private var currentEditPosition = -1 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { val binding = CategoryItemBinding.inflate( LayoutInflater.from(parent.context), parent, false ) return MyViewHolder(binding) } override fun onBindViewHolder(holder: MyViewHolder, position: Int) { val item = categoryList[position] holder.binding.apply { // 根据编辑状态显示对应布局 if (position == currentEditPosition) { categoryName.visibility = View.GONE categoryEditName.visibility = View.VISIBLE categoryEditName.setText(item.name) categoryEditIv.visibility = View.GONE categoryAgreeIv.visibility = View.VISIBLE } else { categoryName.visibility = View.VISIBLE categoryEditName.visibility = View.GONE categoryEditIv.visibility = View.VISIBLE categoryAgreeIv.visibility = View.GONE categoryName.text = item.name } } } override fun getItemCount() = categoryList.size // 对外暴露更新列表的方法,避免重复创建Adapter fun updateList(newList: List<Category>) { categoryList = newList.toMutableList() // 要求不高可以直接用notifyDataSetChanged,性能要求高可替换为DiffUtil实现 notifyDataSetChanged() } inner class MyViewHolder(val binding: CategoryItemBinding) : RecyclerView.ViewHolder(binding.root) { // 点击事件绑定放到ViewHolder初始化,避免每次复用重复绑定 init { // 编辑按钮点击 binding.categoryEditIv.setOnClickListener { val position = adapterPosition if (position == RecyclerView.NO_POSITION) return@setOnClickListener // 先取消之前的编辑状态 val preEditPos = currentEditPosition currentEditPosition = position if (preEditPos != -1) notifyItemChanged(preEditPos) notifyItemChanged(currentEditPosition) } // 确认按钮点击 binding.categoryAgreeIv.setOnClickListener { val position = adapterPosition if (position == RecyclerView.NO_POSITION) return@setOnClickListener val newName = binding.categoryEditName.text.toString().trim() if (newName.isNotEmpty()) { listener.editAgreeClickItem(categoryList[position], newName) } currentEditPosition = -1 notifyItemChanged(position) } // 删除按钮点击 binding.categoryDeleteIv.setOnClickListener { val position = adapterPosition if (position == RecyclerView.NO_POSITION) return@setOnClickListener listener.deleteClickItem(categoryList[position]) } } } interface ClickListener { // 修改回调携带原Category对象和新名称 fun editAgreeClickItem(category: Category, newName: String) fun deleteClickItem(category: Category) } }
2. MainFragment 改造
class MainFragment : Fragment(), NewCategory.NewCategoryCreateListener, CategoryAdapter.ClickListener { private var _binding: FragmentMainBinding? = null private val binding get() = _binding!! private lateinit var shoppingListViewModel: ShoppingListViewModel private lateinit var categoryAdapter: CategoryAdapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) shoppingListViewModel = ViewModelProvider(requireActivity())[ShoppingListViewModel::class.java] } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { _binding = FragmentMainBinding.inflate(layoutInflater, container, false) return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 初始化Adapter只做一次 categoryAdapter = CategoryAdapter(listener = this) binding.categoryRV.apply { layoutManager = LinearLayoutManager(requireContext()) adapter = categoryAdapter } // 观察数据变更只更新Adapter内容,不重复创建实例 shoppingListViewModel.allCategories.observe(viewLifecycleOwner) { updateCategories(it) } binding.addCategory.setOnClickListener { val newCategory = NewCategory(this) newCategory.show(childFragmentManager, "NewCategory") } } private fun updateCategories(list: List<Category>) { if (list.isEmpty()) { binding.noResult.visibility = View.VISIBLE binding.categoryRV.visibility = View.GONE } else { binding.noResult.visibility = View.GONE binding.categoryRV.visibility = View.VISIBLE categoryAdapter.updateList(list) } } override fun newCategoryCreate(text: String) { val newCat = Category(text) shoppingListViewModel.insertCategory(newCat) } override fun editAgreeClickItem(category: Category, newName: String) { // 修改原有Category的名称,携带原有id传给数据库更新 category.name = newName shoppingListViewModel.updateCategory(category) } override fun deleteClickItem(category: Category) { shoppingListViewModel.deleteCategory(category) } override fun onDestroyView() { super.onDestroyView() _binding = null } }
补充说明
如果你的Category类的name字段是val不可修改,可以替换编辑回调的逻辑:构造新的Category对象时传入原有id和新name即可,确保数据库能匹配到对应条目。
内容的提问来源于stack exchange,提问作者Matt
相关产品推荐
相关产品推荐

