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

Android Studio购物车实时更新问题求助(Firebase数据同步)

购物车实时更新问题修复方案

问题现象

  • 执行商品增减、删除操作后,购物车数据无法实时刷新,需切换页面才能看到变化;
  • 删除商品后,该商品仍残留于RecyclerView列表底部,需切换页面才会消失。

现有代码

CartActivity.java

@Override
protected void onStop() {
    if (EventBus.getDefault().hasSubscriberForEvent(MyUpdateCartEvent.class))
        EventBus.getDefault().removeStickyEvent(MyUpdateCartEvent.class);
    EventBus.getDefault().unregister(this);
    super.onStop();
}

@Subscribe(threadMode = ThreadMode.MAIN_ORDERED, sticky = true)
public void onUpdateCart(MyUpdateCartEvent event) {
    loadCartFromFirebase();
}

private void loadCartFromFirebase() {
    fAuth = FirebaseAuth.getInstance();
    if(fAuth.getCurrentUser() != null){
        userId = fAuth.getCurrentUser().getUid();
    } else {
        userId = "UNIQUE_USER_ID";
    }
    List<CartModel> cartModels = new ArrayList<>();
    FirebaseDatabase.getInstance()
            .getReference("cart")
            .child(userId)
            .addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot snapshot) {
                    if (snapshot.exists()) {
                        for (DataSnapshot cartSnapshot : snapshot.getChildren()) {
                            CartModel cartModel = cartSnapshot.getValue(CartModel.class);
                            cartModel.setKey(cartSnapshot.getKey());
                            cartModels.add(cartModel);
                        }
                        cartLoadListener.onCartLoadSuccess(cartModels);
                    } else {
                        cartLoadListener.onCartLoadFailed("Cart Empty");
                    }
                }

                @Override
                public void onCancelled(@NonNull DatabaseError error) {
                    cartLoadListener.onCartLoadFailed(error.getMessage());
                }
            });
}

private void init() {
    ButterKnife.bind(this);

    cartLoadListener = this;
    LinearLayoutManager layoutManager = new LinearLayoutManager(this);
    recycler_cart.setLayoutManager(layoutManager);
    purchScrnBtn.setOnClickListener(v -> startActivity(new Intent(this, PurchaseActivity.class)));

}

@Override
public void onCartLoadSuccess(List<CartModel> cartModelList) {
    double sum = 0;
    for (CartModel cartModel : cartModelList) {
        sum += cartModel.getTotalPrice();
    }
    textTotal.setText(new StringBuilder("$").append(sum));
    MyCartAdapter adapter = new MyCartAdapter(this, cartModelList);
    recycler_cart.setAdapter(adapter);
}

MyCartAdapter.java(注:原代码类名错误,需修正为继承RecyclerView.Adapter)

package com.example.cart.adapter;

public class MyCartAdapter extends RecyclerView.Adapter<MyCartAdapter.MyCartViewHolder> {
    private Context context;
    private List<CartModel> cartModelList;
    private String userId;

    public MyCartAdapter(Context context, List<CartModel> cartModelList) {
        this.context = context;
        this.cartModelList = cartModelList;
        FirebaseAuth fAuth = FirebaseAuth.getInstance();
        userId = fAuth.getCurrentUser() != null ? fAuth.getCurrentUser().getUid() : "UNIQUE_USER_ID";
    }

    @NonNull
    @Override
    public MyCartViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new MyCartViewHolder(LayoutInflater.from(context)
                .inflate(R.layout.layout_cart_item, parent, false));
    }

    @Override
    public void onBindViewHolder(@NonNull MyCartViewHolder holder, int position) {
        holder.txtQuantity.setText(String.valueOf(cartModelList.get(position).getQuantity()));

        holder.minus.setOnClickListener(v -> {
            minusCartItem(holder, cartModelList.get(position), position);
        });
        
        holder.delete.setOnClickListener(v -> {
            AlertDialog dialog = new AlertDialog.Builder(context)
                    .setTitle("Delete item")
                    .setMessage("Do you really want to delete item")
                    .setNegativeButton("CANCEL", (dialogInterface, i) -> dialogInterface.dismiss())
                    .setPositiveButton("OK", (dialogInterface2, i) -> {
                        notifyItemRemoved(position);
                        deleteFromFirebase(cartModelList.get(position));
                        dialogInterface2.dismiss();
                    }).create();
            dialog.show();
        });
    }

    @Override
    public int getItemCount() {
        return cartModelList.size();
    }

    private void deleteFromFirebase(CartModel cartModel) {
        FirebaseDatabase.getInstance()
                .getReference("cart")
                .child(userId)
                .child(cartModel.getKey())
                .removeValue()
                .addOnSuccessListener(aVoid -> EventBus.getDefault().postSticky(new MyUpdateCartEvent()));
    }

    @SuppressLint("SuspiciousIndentation")
    private void minusCartItem(MyCartViewHolder holder, CartModel cartModel) {
        if(cartModel.getQuantity() > 1)
            cartModel.setQuantity(cartModel.getQuantity()-1);
            cartModel.setTotalPrice(cartModel.getQuantity()*Float.parseFloat(cartModel.getPrice()));

            holder.txtQuantity.setText(new StringBuilder().append(cartModel.getQuantity()));
            updateFirebase(cartModel);
    }

    private void updateFirebase(CartModel cartModel) {
        FirebaseDatabase.getInstance()
                .getReference("cart")
                .child(userId)
                .child(cartModel.getKey())
                .setValue(cartModel);
    }

    public class MyCartViewHolder extends RecyclerView.ViewHolder{
        @BindView(R.id.txt_quantity)
        TextView txtQuantity;
        @BindView(R.id.minus)
        ImageView minus;
        @BindView(R.id.delete)
        ImageView delete;

        Unbinder unbinder;

        public MyCartViewHolder(@NonNull View itemView) {
            super(itemView);
            unbinder = ButterKnife.bind(this, itemView);
        }
    }
}

修复步骤

1. 解决数据实时更新问题

替换Firebase单次监听为实时监听

addListenerForSingleValueEvent仅读取一次数据,改用addValueEventListener可监听Firebase数据变化,自动触发页面刷新:

private ValueEventListener cartValueEventListener;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // ...其他初始化代码
    loadCartFromFirebase();
}

private void loadCartFromFirebase() {
    fAuth = FirebaseAuth.getInstance();
    userId = fAuth.getCurrentUser() != null ? fAuth.getCurrentUser().getUid() : "UNIQUE_USER_ID";
    
    cartValueEventListener = new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot snapshot) {
            List<CartModel> cartModels = new ArrayList<>();
            if (snapshot.exists()) {
                for (DataSnapshot cartSnapshot : snapshot.getChildren()) {
                    CartModel cartModel = cartSnapshot.getValue(CartModel.class);
                    cartModel.setKey(cartSnapshot.getKey());
                    cartModels.add(cartModel);
                }
                cartLoadListener.onCartLoadSuccess(cartModels);
            } else {
                cartLoadListener.onCartLoadFailed("购物车为空");
            }
        }

        @Override
        public void onCancelled(@NonNull DatabaseError error) {
            cartLoadListener.onCartLoadFailed(error.getMessage());
        }
    };

    FirebaseDatabase.getInstance()
            .getReference("cart")
            .child(userId)
            .addValueEventListener(cartValueEventListener);
}

// 页面销毁时移除监听,避免内存泄漏
@Override
protected void onDestroy() {
    super.onDestroy();
    if (cartValueEventListener != null) {
        FirebaseDatabase.getInstance()
                .getReference("cart")
                .child(userId)
                .removeEventListener(cartValueEventListener);
    }
}

优化适配器实例复用

避免每次刷新都创建新适配器,复用现有实例提升性能:

private MyCartAdapter cartAdapter;

@Override
public void onCartLoadSuccess(List<CartModel> cartModelList) {
    double sum = 0;
    for (CartModel cartModel : cartModelList) {
        sum += cartModel.getTotalPrice();
    }
    textTotal.setText(new StringBuilder("$").append(sum));
    
    if (cartAdapter == null) {
        cartAdapter = new MyCartAdapter(this, cartModelList);
        recycler_cart.setAdapter(cartAdapter);
    } else {
        cartAdapter.updateList(cartModelList);
    }
}

在MyCartAdapter中添加列表更新方法:

public void updateList(List<CartModel> newList) {
    cartModelList.clear();
    cartModelList.addAll(newList);
    notifyDataSetChanged();
}

2. 解决删除后商品残留问题

同步本地列表与适配器状态

删除操作需先修改本地列表,再通知适配器更新,确保数据一致性:

holder.delete.setOnClickListener(v -> {
    AlertDialog dialog = new AlertDialog.Builder(context)
            .setTitle("删除商品")
            .setMessage("确定要删除该商品吗?")
            .setNegativeButton("取消", (dialogInterface, i) -> dialogInterface.dismiss())
            .setPositiveButton("确定", (dialogInterface2, i) -> {
                // 1. 从本地列表移除数据
                CartModel removedItem = cartModelList.remove(position);
                // 2. 通知适配器移除该项
                notifyItemRemoved(position);
                // 3. 通知后续项位置更新
                notifyItemRangeChanged(position, cartModelList.size());
                // 4. 删除Firebase数据
                deleteFromFirebase(removedItem);
                dialogInterface2.dismiss();
            }).create();
    dialog.show();
});

修正增减商品的局部更新逻辑

增减商品时同步更新本地列表并通知适配器局部刷新:

private void minusCartItem(MyCartViewHolder holder, CartModel cartModel, int position) {
    if(cartModel.getQuantity() > 1) {
        cartModel.setQuantity(cartModel.getQuantity()-1);
        cartModel.setTotalPrice(cartModel.getQuantity() * Float.parseFloat(cartModel.getPrice()));
        
        // 更新本地列表
        cartModelList.set(position, cartModel);
        // 通知适配器局部更新
        notifyItemChanged(position);
        updateFirebase(cartModel);
    }
}

内容的提问来源于stack exchange,提问作者Gervin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 21:50:24