电商APP购物车删除商品后总计金额未实时更新问题
电商APP购物车金额更新异常问题
问题现象:添加两个商品到购物车后删除其中一个,购物车总计金额无法实时正确更新,仅在关闭并重新打开MyCartFragment后才显示正确数值。
相关代码
1. CartItemModel类(数据结构定义)
@Parcelize data class CartItemModel( var type: Int?, var productId: String?, var productImage: String?, var productName: String?, var freeCoupons: Long?, var productPrice: String?, var cuttedPrice: String?, var productQuantity: Long?, var maxQuantity: Long?, var stockQuantity: Long?, var offersApply: Long?, var couponsApplied: Long?, var inStock: Boolean?, var qtyIDs: ArrayList<String>?, var selectedCouponId: String?, var discountedPrice: String?, var totalItems: Int?, var totalItemsPrice: Int?, var deliveryPrice: String?, var totalAmount: Int?, var savedAmount: Int? ) : Parcelable { constructor(type: Int) : this( type, productId = null, productImage = null, productName = null, freeCoupons = null, productPrice = null, cuttedPrice = null, productQuantity = null, maxQuantity = null, stockQuantity = null, offersApply = null, couponsApplied = null, inStock = null, qtyIDs = null, selectedCouponId = null, discountedPrice = null, totalItems = null, totalItemsPrice = null, deliveryPrice = null, totalAmount = null, savedAmount = null ) { this.type = type } constructor( type: Int, totalItems: Int, totalItemsPrice: Int, deliveryPrice: String, totalAmount: Int, savedAmount: Int ) : this( type, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, totalItems, totalItemsPrice, deliveryPrice, totalAmount, savedAmount ) companion object { const val CART_ITEM = 0 const val TOTAL_AMOUNT = 1 } }
2. CartAdapter类核心方法(总计金额计算逻辑)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return when (viewType) { CartItemModel.CART_ITEM -> { val cartItemLayoutBinding: CartItemLayoutBinding = CartItemLayoutBinding.inflate( LayoutInflater.from(parent.context), parent, false ) CartItemViewHolder(cartItemLayoutBinding) } CartItemModel.TOTAL_AMOUNT -> { val cartTotalAmountLayoutBinding: CartTotalAmountLayoutBinding = CartTotalAmountLayoutBinding.inflate( LayoutInflater.from(parent.context), parent, false ) CartTotalAmountViewHolder(cartTotalAmountLayoutBinding) } else -> { val cartItemLayoutBinding: CartItemLayoutBinding = CartItemLayoutBinding.inflate( LayoutInflater.from(parent.context), parent, false ) CartItemViewHolder(cartItemLayoutBinding) } } } override fun onBindViewHolder( holder: RecyclerView.ViewHolder, @SuppressLint("RecyclerView") position: Int ) { when (asyncListDiffer.currentList[position].type) { CartItemModel.CART_ITEM -> { val cartItemModel: CartItemModel = asyncListDiffer.currentList[position] (holder as CartItemViewHolder).bind(cartItemModel, position) if (lastPosition < position) { val animation = AnimationUtils.loadAnimation( holder.itemView.context, R.anim.fade_in ) holder.itemView.animation = animation lastPosition = position } } CartItemModel.TOTAL_AMOUNT -> { var totalItems = 0 var totalItemsPrice = 0 val deliveryPrice: String val totalAmount: Int var savedAmount = 0 for (i in 0 until asyncListDiffer.currentList.size) { if (asyncListDiffer.currentList[i].type == CartItemModel.CART_ITEM && asyncListDiffer.currentList[i].inStock == true) { val quantity = asyncListDiffer.currentList[i].productQuantity totalItems = (totalItemsPrice + quantity!!).toInt() totalItemsPrice += if (asyncListDiffer.currentList[position].selectedCouponId.isNullOrEmpty()) { asyncListDiffer.currentList[i].productPrice?.toInt()!! * quantity.toInt() } else { asyncListDiffer.currentList[i].discountedPrice?.toInt()!! * quantity.toInt() } if (asyncListDiffer.currentList[i].cuttedPrice?.isNotEmpty()!!) { savedAmount += (asyncListDiffer.currentList[i].cuttedPrice?.toInt()!! - asyncListDiffer.currentList[i].productPrice?.toInt()!!) * quantity.toInt() if (!asyncListDiffer.currentList[position].selectedCouponId.isNullOrEmpty()) { savedAmount += (asyncListDiffer.currentList[i].productPrice?.toInt()!! - asyncListDiffer.currentList[i].discountedPrice?.toInt()!!) * quantity.toInt() } } else { if (asyncListDiffer.currentList[position].selectedCouponId?.isNotEmpty()!!) { savedAmount += (asyncListDiffer.currentList[i].productPrice?.toInt()!! - asyncListDiffer.currentList[i].discountedPrice?.toInt()!!) * quantity.toInt() } } } } if (totalItemsPrice > 500) { deliveryPrice = "Free" totalAmount = totalItemsPrice } else { deliveryPrice = "60" totalAmount = totalItemsPrice + 60 } asyncListDiffer.currentList[position].totalItems = totalItems asyncListDiffer.currentList[position].totalItemsPrice = totalItemsPrice asyncListDiffer.currentList[position].deliveryPrice = deliveryPrice asyncListDiffer.currentList[position].totalAmount = totalAmount asyncListDiffer.currentList[position].savedAmount = savedAmount Log.d(TAG, "onBindViewHolder: totalItems $totalItems") Log.d(TAG, "onBindViewHolder: totalItems $totalItemsPrice") Log.d(TAG, "onBindViewHolder: totalItems $deliveryPrice") Log.d(TAG, "onBindViewHolder: totalItems $totalAmount") Log.d(TAG, "onBindViewHolder: totalItems $savedAmount") (holder as CartTotalAmountViewHolder).setTotalAmount( totalItems, totalItemsPrice, deliveryPrice, totalAmount, savedAmount ) myCartUtil?.getTotalAmount(totalAmount) if (lastPosition < position) { val animation = AnimationUtils.loadAnimation( holder.itemView.context, R.anim.fade_in ) holder.itemView.animation = animation lastPosition = position } } else -> return } }
问题根源分析
- 数据变更未触发Adapter更新:删除商品后仅修改了数据源,但未通过
AsyncListDiffer.submitList()提交新列表,导致Adapter未重新执行总计金额计算逻辑。 - 总计计算依赖UI绑定时机:总计金额计算仅在
onBindViewHolder中执行,删除商品后TOTAL_AMOUNT项的绑定逻辑不会自动触发,因为AsyncListDiffer未检测到该项数据变化。 - 直接修改列表项属性无效:代码中直接修改
asyncListDiffer.currentList中项的属性,但AsyncListDiffer基于不可变列表对比,这种修改无法被检测到,无法触发UI更新。 - 总商品数计算错误:
totalItems = (totalItemsPrice + quantity!!).toInt()逻辑错误,用总价加数量计算总商品数,导致数值完全错误。
修复方案
1. 修正总商品数计算逻辑
把错误的总商品数计算代码:
totalItems = (totalItemsPrice + quantity!!).toInt()
替换为:
totalItems += quantity!!.toInt()
2. 数据变更时提交新列表
删除商品后,重新计算总计金额并生成全新列表提交给AsyncListDiffer,触发UI更新:
// 删除指定位置商品后执行 val newList = asyncListDiffer.currentList.toMutableList() newList.removeAt(deletePosition) // 移除旧的总计项,重新计算并添加新的总计项 newList.removeAll { it.type == CartItemModel.TOTAL_AMOUNT } newList.add(calculateTotalAmount(newList)) // 提交新列表触发更新 asyncListDiffer.submitList(newList)
3. 提取总计计算为独立方法
将总计金额逻辑从onBindViewHolder中剥离,提前计算好再提交:
private fun calculateTotalAmount(list: List<CartItemModel>): CartItemModel { var totalItems = 0 var totalItemsPrice = 0 var savedAmount = 0 for (item in list) { if (item.type == CartItemModel.CART_ITEM && item.inStock == true) { val quantity = item.productQuantity ?: 0 totalItems += quantity.toInt() totalItemsPrice += if (item.selectedCouponId.isNullOrEmpty()) { (item.productPrice?.toInt() ?: 0) * quantity.toInt() } else { (item.discountedPrice?.toInt() ?: 0) * quantity.toInt() } if (!item.cuttedPrice.isNullOrEmpty()) { savedAmount += ((item.cuttedPrice?.toInt() ?: 0) - (item.productPrice?.toInt() ?: 0)) * quantity.toInt() if (!item.selectedCouponId.isNullOrEmpty()) { savedAmount += ((item.productPrice?.toInt() ?: 0) - (item.discountedPrice?.toInt() ?: 0)) * quantity.toInt() } } else if (!item.selectedCouponId.isNullOrEmpty()) { savedAmount += ((item.productPrice?.toInt() ?: 0) - (item.discountedPrice?.toInt() ?: 0)) * quantity.toInt() } } } val deliveryPrice = if (totalItemsPrice > 500) "Free" else "60" val totalAmount = totalItemsPrice + if (deliveryPrice != "Free") 60 else 0 return CartItemModel( type = CartItemModel.TOTAL_AMOUNT, totalItems = totalItems, totalItemsPrice = totalItemsPrice, deliveryPrice = deliveryPrice, totalAmount = totalAmount, savedAmount = savedAmount ) }
内容的提问来源于stack exchange,提问作者Dr Mido
相关产品推荐
相关产品推荐

