Firebase嵌套ArrayList数据读取异常:无法完整获取日期字段及存值为null
嘿,我来帮你一步步搞定这些问题,让你的数据能正确读取并展示在ListView里:
问题根源分析与逐个解决
1. 无法读取datedata下的month和year字段
你的DateDataHelper类里有一个多余的带AccountBillList参数的构造函数,Firebase在反序列化数据时会优先匹配参数匹配的构造,这个空实现的构造会导致字段完全没被赋值。另外,Firebase要求实体类必须有无参构造函数,否则反序列化直接失败。
解决方案:
- 删除那个带Activity参数的无用构造函数
- 添加一个空实现的无参构造(Firebase反序列化必须)
- 确保构造函数的参数名和Firebase节点里的字段名完全一致(你的代码里这点已经没问题)
2. 日期值存入ArrayList时显示为null
你声明的所有ArrayList(account、amount、date、month、year)都只是定义了变量,没有初始化实例!比如ArrayList<String> account;只是声明,没有new ArrayList<>(),调用add()时不仅会触发空指针,调试时自然显示为null。
解决方案:
初始化集合时一定要创建实例:
ArrayList<String> account = new ArrayList<>(); ArrayList<String> amount = new ArrayList<>(); ArrayList<String> date = new ArrayList<>(); ArrayList<String> month = new ArrayList<>(); ArrayList<String> year = new ArrayList<>();
3. 第二个for循环处理account和amount的逻辑问题
原来的逻辑里,外层循环每个purchasebill节点时先添加account和amount,再内层循环遍历datedata添加日期字段。但如果一个purchasebill有多个datedata,同一个account和amount会被对应到多个日期,而ListView需要的是每个条目对应一组完整日期+account+amount,分开存储多个ArrayList很容易导致数据错位。
更优解决方案:
创建一个专门的实体类封装ListView每个条目的数据,比如BillItem:
public class BillItem { private String fullDate; private String account; private String amount; // 无参构造,Firebase反序列化必须 public BillItem() {} public BillItem(String fullDate, String account, String amount) { this.fullDate = fullDate; this.account = account; this.amount = amount; } // getter和setter方法 public String getFullDate() { return fullDate; } public void setFullDate(String fullDate) { this.fullDate = fullDate; } public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public String getAmount() { return amount; } public void setAmount(String amount) { this.amount = amount; } }
用ArrayList<BillItem>存储所有条目,数据对应关系绝对不会乱。
修正后的完整代码示例
1. 修正后的DateDataHelper类
class DateDataHelper { private String date; private String month; private String year; // 无参构造,Firebase反序列化必须 public DateDataHelper() {} public DateDataHelper(String date, String month, String year) { this.date = date; this.month = month; this.year = year; } // getter and setter方法 public String getDate() { return date; } public void setDate(String date) { this.date = date; } public String getMonth() { return month; } public void setMonth(String month) { this.month = month; } public String getYear() { return year; } public void setYear(String year) { this.year = year; } }
2. 修正后的Firebase数据读取逻辑
// 用封装好的BillItem集合存储数据 ArrayList<BillItem> billItemList = new ArrayList<>(); BillListAdapter billListAdapter = new BillListAdapter(AccountBillList.this, billItemList); // 适配你的Adapter myRef = database.getReference("purchasebill"); myRef.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot dataSnapshot) { // 每次数据变化先清空集合,避免重复添加 billItemList.clear(); for (DataSnapshot ds : dataSnapshot.getChildren()) { BilllistHelper billlistHelper = ds.getValue(BilllistHelper.class); if (billlistHelper == null) continue; // 空判断,避免空指针 String account = billlistHelper.getAccount(); String amount = billlistHelper.getAmount(); // 遍历当前purchasebill下的所有datedata节点 for (DataSnapshot dd : ds.child("datedata").getChildren()){ DateDataHelper dateDataHelper = dd.getValue(DateDataHelper.class); if (dateDataHelper == null) continue; // 拼接完整日期,格式可自行调整 String fullDate = dateDataHelper.getDate() + "/" + dateDataHelper.getMonth() + "/" + dateDataHelper.getYear(); // 创建BillItem并添加到集合 billItemList.add(new BillItem(fullDate, account, amount)); } // 若需处理intendby和vendorname,可在BillItem中添加对应字段 // intendby.add(billlistHelper.getIntendby()); // vendorname.add(billlistHelper.getVendorName()); } billListAdapter.notifyDataSetChanged(); } @Override public void onCancelled(@NonNull DatabaseError databaseError) { // 处理数据读取失败的情况 Log.e("FirebaseError", "数据读取失败: " + databaseError.getMessage()); } });
3. 对应的Adapter修改(示例)
你的BillListAdapter需要适配BillItem类,在getView方法中获取对应字段:
@Override public View getView(int position, View convertView, ViewGroup parent) { // 初始化View等逻辑... BillItem item = billItemList.get(position); tvFullDate.setText(item.getFullDate()); tvAccount.setText(item.getAccount()); tvAmount.setText(item.getAmount()); return convertView; }
这样修改后,三个问题就都解决了:Firebase能正确反序列化datedata的所有字段,集合不会再出现null,数据对应关系也不会错乱,ListView能正确展示每个条目的完整日期、account和amount。
内容的提问来源于stack exchange,提问作者bhim jairu

