Android Kotlin中使用RoomDB更新购物车并计算总价问题排查
问题排查与解决方案
问题根源
- 内存集合与Room不同步:更新Room数据库后,未同步更新Adapter持有的
listItems集合,导致计算总价时使用旧数据。 - 总价计算依赖初始化集合:Fragment的
onUpdateTotal回调直接使用初始化时的listitem集合,该集合未随Room更新。 - Adapter资源初始化冗余:
onBindViewHolder中重复初始化database和dao,造成不必要的资源消耗。 - 局部变量导致状态丢失:增减按钮的
itemcart为局部变量,切换toggle按钮会重置库存,且未从现有Cart对象读取当前库存值。
修复步骤
1. 优化CartAdapter,同步内存与Room数据
class CartAdapter( private val context: Context, private val listItems: ArrayList<Cart>, private val listener: OnAdapterListener ) : RecyclerView.Adapter<CartAdapter.CartViewHolder>() { private val dao: CartDao interface OnAdapterListener{ fun onUpdateTotal() } // 初始化数据库连接到构造函数 init { val database = CartRoomDatabase.getDatabase(context) dao = database.getCartDao() } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CartViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.itemcart, parent, false) return CartViewHolder(view) } override fun onBindViewHolder(holder: CartViewHolder, position: Int) { val item = listItems[position] holder.tv_namaproduk.text = item.namaproduk holder.tv_stokproduk.text = item.stokproduk.toString() holder.tv_hargaproduk.text = (item.stokproduk * item.hargaproduk).toString() Glide.with(holder.iv_gambarproduk) .load(item.gambarproduk) .error(R.drawable.bannerwelcome) .into(holder.iv_gambarproduk) // 从当前item读取库存作为初始值 var itemcart = item.stokproduk holder.itemView.togglebtneg.addOnButtonCheckedListener { _, checkedId, isChecked -> if (isChecked){ when(checkedId){ R.id.btn_ecer ->{ holder.itemView.iv_tambahstok.setOnClickListener { itemcart++ updateItemAndDatabase(position, itemcart) updateItemUI(holder, itemcart, item.hargaproduk) listener.onUpdateTotal() } holder.itemView.iv_kurangstok.setOnClickListener { if (itemcart > 0) { itemcart-- updateItemAndDatabase(position, itemcart) updateItemUI(holder, itemcart, item.hargaproduk) listener.onUpdateTotal() } } } R.id.btn_grosir ->{ holder.itemView.iv_tambahstok.setOnClickListener { itemcart +=5 updateItemAndDatabase(position, itemcart) updateItemUI(holder, itemcart, item.hargaproduk) listener.onUpdateTotal() } holder.itemView.iv_kurangstok.setOnClickListener { if (itemcart >=5) { itemcart -=5 updateItemAndDatabase(position, itemcart) updateItemUI(holder, itemcart, item.hargaproduk) listener.onUpdateTotal() } } } } } } holder.itemView.iv_deletecart.setOnClickListener { dao.delete(item) listItems.removeAt(position) notifyItemRemoved(position) notifyItemRangeChanged(position, listItems.size) listener.onUpdateTotal() } } override fun getItemCount(): Int = listItems.size // 同步更新内存集合与数据库 private fun updateItemAndDatabase(position: Int, newStock: Int) { val updatedCart = listItems[position].copy(stokproduk = newStock) dao.update(updatedCart) listItems[position] = updatedCart notifyItemChanged(position) } // 更新单个item的UI private fun updateItemUI(holder: CartViewHolder, stock: Int, price: Int) { holder.tv_stokproduk.text = stock.toString() holder.tv_hargaproduk.text = (stock * price).toString() } class CartViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val tv_namaproduk = itemView.findViewById<TextView>(R.id.tv_namaprodukfin) val tv_hargaproduk = itemView.findViewById<TextView>(R.id.tv_hargaprodukfin) val tv_stokproduk = itemView.findViewById<TextView>(R.id.tv_banyakstok) val iv_gambarproduk = itemView.findViewById<ImageView>(R.id.iv_cartitem) } }
2. 修复KeranjangFragment的总价计算逻辑
确保总价计算使用最新数据,可选两种方案:
private fun getCartList() { val sharedpreferencesLogged = requireActivity().getSharedPreferences("sp_login", android.content.Context.MODE_PRIVATE) val loginid = sharedpreferencesLogged.getString("login_id", null) val database = CartRoomDatabase.getDatabase(requireContext().applicationContext) val dao = database.getCartDao() val listitem = arrayListOf<Cart>() listitem.addAll(dao.getAll()) if(loginid == null){ scrollview_profile_keranjang.visibility = View.VISIBLE ln_filledcart.visibility = View.INVISIBLE ln_emptycart.visibility = View.INVISIBLE }else{ scrollview_profile_keranjang.visibility = View.INVISIBLE if (listitem.size == 0){ ln_filledcart.visibility = View.INVISIBLE ln_emptycart.visibility = View.VISIBLE } else { ln_filledcart.visibility = View.VISIBLE rv_cartitem.layoutManager = LinearLayoutManager(activity) val adaptertemp = CartAdapter(requireContext(), listitem, object : CartAdapter.OnAdapterListener{ override fun onUpdateTotal() { // 方案1:使用已同步的内存集合计算 var sum = 0 listitem.forEach { cart -> sum += cart.hargaproduk * cart.stokproduk } tv_total.text = sum.toString() // 方案2:从Room重新获取最新数据(更可靠) // val latestItems = dao.getAll() // var sum = 0 // latestItems.forEach { cart -> // sum += cart.hargaproduk * cart.stokproduk // } // tv_total.text = sum.toString() } }) rv_cartitem.adapter = adaptertemp ln_emptycart.visibility = View.INVISIBLE } } }
3. 额外优化建议
- 使用Room的
LiveData监听数据变化:将dao.getAll()改为返回LiveData<List<Cart>>,Fragment中观察LiveData,数据更新时自动刷新Adapter和总价。 - 避免在
onBindViewHolder中重复设置点击监听器,改为在onCreateViewHolder中绑定,通过holder.adapterPosition获取位置。
内容的提问来源于stack exchange,提问作者Random Thought
相关产品推荐
相关产品推荐

