Firebase实时数据库更新List类型对象二次保存报错求助
Firebase Realtime Database更新List属性时二次保存报错问题
问题概述
首次保存包含List<Users>属性的Bill对象到Firebase Realtime Database时正常,但二次更新usersList(列表长度或元素值变化)时出现报错,提示无法将ArrayList类型转换为Users对象(对应原问题报错截图内容)。
Bill模型代码
public class Bill implements Serializable, Comparable<Bill> { private List<Users> usersList; }
核心保存代码
mDatabase .child(Global.FD_TABLE_CREATE_BILL+Global.GLOBAL_DB_PARAMETER+users.getTenant().getId()) .child(bill.getBillID()).setValue(bill) .addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void aVoid) { new Handler().postDelayed(new Runnable() { @Override public void run (){ //do something here } }, /* 补充延迟时间常量 */) } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { e.printStackTrace(); } });
完整处理方法代码
public void validatePaymentBeforeUpdateUserSelectedForBill(final Context context,final FirebaseDatabase mFirebaseInstance,final DatabaseReference mDatabase,final List<String> lastSelectedUser,final Bill bill,final List<Users> usersList,final Users users, final HomeCollaborationModel homeCollaborationModel, final List<MasterPayment> masterPayment,final List<BankList> masterBankLists, final UserRoles userRoles,final List<PaymentMax> paymentMaxList) { final boolean[] failedValidation = {false}; FirebaseDatabase firebaseDatabase = FirebaseDatabase.getInstance(); final DatabaseReference dataReference = firebaseDatabase.getReference().child(Global.FD_TABLE_PAYMENT + Global.GLOBAL_DB_PARAMETER + users.getTenant().getId()); final boolean[] gotResult = new boolean[1]; gotResult[0] = false; final Query queryData; queryData = dataReference.orderByChild("billID").equalTo(bill.getBillID()); final ValueEventListener dataFetchEventListener = new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { // Get user information if (dataSnapshot.exists()) { DatabaseReference mDatabaseLocal = mDatabase; List<PaymentConfirmation> paymentConfirmationList = new ArrayList<PaymentConfirmation>(); gotResult[0] = true; for (DataSnapshot messageSnapshot : dataSnapshot.getChildren()) { PaymentConfirmation bill = messageSnapshot.getValue(PaymentConfirmation.class); if (bill != null) { paymentConfirmationList.add(bill); } } if (paymentConfirmationList.size() > 0){ List<Users> userses = new ArrayList<Users>(); for (int i =0;i < getSelectedStrings().size(); i++){ for (int j =0; j < usersList.size(); j ++){ String userListValue = usersList.get(j).getName()+" -> "+usersList.get(j).getTenant().getUniqueData(); if (getSelectedStrings().get(i).toString().trim().equals(userListValue.trim())){ userses.add(usersList.get(j)); } } } for (PaymentConfirmation paymentConfirmation : paymentConfirmationList){ boolean isExistOnUserSelected = false; for (Users usersSelected: userses){ if (paymentConfirmation.getCreatedBy().getId().equals(usersSelected.getId())){ isExistOnUserSelected = true; break; }else{ isExistOnUserSelected = false; } } if (!isExistOnUserSelected){ for (Users userData: usersList){ if (paymentConfirmation.getCreatedBy().getId().equals(userData.getId())){ userses.add(userData); break; } } } } if(userses.size() > 0){ bill.setUsersList(userses); } mDatabase.child(Global.FD_TABLE_CREATE_BILL+Global.GLOBAL_DB_PARAMETER+users.getTenant().getId()) .child(bill.getBillID()).setValue(bill) .addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void aVoid) { new Handler().postDelayed(new Runnable() { @Override public void run (){ String[] serializablesName = {"Users","HomeCollaborationModel","MasterPayment","userRoles","openedBy","callbackBillID","BankList","PaymentMaxList"}; Serializable[] serializables = {users,homeCollaborationModel, (Serializable) masterPayment,userRoles,2,bill.getBillID(),(Serializable) masterBankLists, (Serializable) paymentMaxList}; IntentController.globalIntent(context, BillContainer.class, serializablesName, serializables,0,true, true); } }, Global.SPLASH_DISPLAY_LENGHT); } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { e.printStackTrace(); } }); }else{ Toast.makeText(context, "Error", Toast.LENGTH_LONG).show(); } } } @Override public void onCancelled(DatabaseError databaseError) { } }; queryData.addListenerForSingleValueEvent(dataFetchEventListener); }
解决方案
1. 确保Users类符合Firebase序列化要求
- 给Users类添加无参构造函数,Firebase依赖该构造函数完成对象反序列化:
public Users() { // 无参构造函数,必须存在 } - 确保Users类的属性为public,或提供对应的getter/setter方法,Firebase需要访问这些属性进行序列化。
2. 避免泛型擦除导致的类型转换问题
将Bill类中的List<Users>改为ArrayList<Users>,显式指定集合类型:
public class Bill implements Serializable, Comparable<Bill> { private ArrayList<Users> usersList; // 对应的setter方法 public void setUsersList(ArrayList<Users> usersList) { this.usersList = usersList; } }
同时在处理代码中,将userses的声明改为ArrayList<Users>,保持类型一致。
3. 使用局部属性更新替代全量setValue
二次更新时无需保存整个Bill对象,仅更新usersList属性,减少序列化风险:
// 替换原有的setValue(bill)代码 Map<String, Object> updates = new HashMap<>(); updates.put("usersList", userses); mDatabase.child(Global.FD_TABLE_CREATE_BILL+Global.GLOBAL_DB_PARAMETER+users.getTenant().getId()) .child(bill.getBillID()) .updateChildren(updates) .addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void aVoid) { // 成功逻辑 } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { e.printStackTrace(); } });
4. 检查循环引用问题
如果Users类中持有Bill对象的引用,会导致Firebase序列化时出现循环引用错误,需用@Exclude注解标记不需要序列化的属性:
public class Users { @Exclude private Bill relatedBill; // 排除该属性,避免循环引用 }
5. 确保数据实例的一致性
二次更新前,避免复用已被修改的Bill实例,可重新从Firebase拉取最新的Bill对象,或初始化新的List对象,防止因对象状态异常导致的序列化失败。
内容的提问来源于stack exchange,提问作者OzanNetwork
相关产品推荐
相关产品推荐

