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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 21:40:27