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

电商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
    }
}

问题根源分析

  1. 数据变更未触发Adapter更新:删除商品后仅修改了数据源,但未通过AsyncListDiffer.submitList()提交新列表,导致Adapter未重新执行总计金额计算逻辑。
  2. 总计计算依赖UI绑定时机:总计金额计算仅在onBindViewHolder中执行,删除商品后TOTAL_AMOUNT项的绑定逻辑不会自动触发,因为AsyncListDiffer未检测到该项数据变化。
  3. 直接修改列表项属性无效:代码中直接修改asyncListDiffer.currentList中项的属性,但AsyncListDiffer基于不可变列表对比,这种修改无法被检测到,无法触发UI更新。
  4. 总商品数计算错误: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 22:01:02