本文介绍在三层嵌套 recyclerview(商店 → 商品 → 附加项)场景下,如何可靠地汇总每家店铺的商品总金额(含数量与附加项价格),避免因 adapter 生命周期和 viewholder 复用导致的总价计算失效问题。核心方案是**预计算、解耦数据与 ui**。
在 Android 开发中,使用嵌套 RecyclerView 实现复杂购物车结构(如:CartStoreAdapter → CartItemAdapter → CartItemAddonAdapter)虽能灵活展示层级数据,但极易陷入「UI 驱动计算」的陷阱——即在 onBindViewHolder() 中边渲染边累加总价(如 totalItems += subTotal)。这种做法看似直观,实则存在严重缺陷:
- ✅ ViewHolder 是可复用的,bind() 可能被多次调用(如滑动后重新绑定),导致 totalItems 被重复累加;
- ❌ totalItems 是 CartItemAdapter 的实例变量,但每个 CartStoreModel 对应一个独立的 CartItemAdapter 实例,其生命周期短且不可控;
- ❌ 在 CartStoreAdapter.ItemRowHolder.bind() 中调用 cartItemAdapter.getTotalItems() 时,该 Adapter 尚未完成全部 onBindViewHolder() 执行(Recycler View 异步绑定机制),返回值恒为初始值(如 0.0)。
✅ 正确解法:数据层预计算(推荐 ViewModel + 不可变模型)
将价格聚合逻辑从 UI 层彻底剥离,交由 ViewModel 或 Repository 层在数据准备阶段完成。确保 CartStoreModel 携带最终所需的 storeTotalPrice 字段,Adapter 仅负责展示。
步骤 1:增强数据模型
为 CartStoreModel 添加只读总价字段(避免运行时意外修改):
public class CartStoreModel {
private String nama_merchant;
private List cartItem;
private double storeTotalPrice; // ← 新增:预计算的本店总价
// 构造时传入已计算好的总价
public CartStoreModel(String nama_merchant, List cartItem, double storeTotalPrice) {
this.nama_merchant = nama_merchant;
this.cartItem = cartItem;
this.storeTotalPrice = storeTotalPrice;
}
// Getter only
public double getStoreTotalPrice() { return storeTotalPrice; }
// ... 其他 getter/setter
}
步骤 2:在 ViewModel 中执行聚合计算(主线程安全)
public class CartViewModel extends ViewModel {
private final MutableLiveData<List> cartStoreData = new MutableLiveData();
public LiveData<List> getCartStoreData() {
return cartStoreData;
}
// 调用此方法初始化带总价的数据
public void loadCartWithTotals(List rawStores) {
List storesWithTotals = new ArrayList();
for (CartStoreModel store : rawStores) {
double storeTotal = calculateStoreTotal(store);
storesWithTotals.add(new CartStoreModel(
store.getNama_merchant(),
store.getCartItem(),
storeTotal
));
}
cartStoreData.postValue(storesWithTotals); // 安全更新 UI
}
private double calculateStoreTotal(CartStoreModel store) {
double total = 0.0;
for (CartItemModel item : store.getCartItem()) {
double itemBasePrice = item.getHarga_promo() > 0 ? item.getHarga_promo() : item.getHarga_item();
double addonPrice = item.getCartItemVar().stream()
.mapToDouble(CartItemVarModel::getVar_price)
.sum();
double itemCost = (itemBasePrice + addonPrice) * item.getQty();
total += itemCost;
}
return total;
}
}
? 提示:若商品量极大(>1000 条),可将 calculateStoreTotal() 放入 viewModelScope.launch(Dispatchers.Default) 中异步执行,避免阻塞主线程。
步骤 3:简化 Adapter,专注展示
CartStoreAdapter 不再创建子 Adapter 后立即读取总价,而是直接使用模型中已计算好的值: