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
相关产品推荐
相关产品推荐

