You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Firestore嵌套HashMap值求和报错及最优实现方案求助

解决Firestore嵌套HashMap求和问题及页面传值方案

先给你理清楚当前的两个核心问题:一是Long::longValue的编译错误,二是你填充外层HashMap的逻辑有bug(会覆盖之前的chapter数据),最后再讲怎么把求和结果传到图表页面。

1. 修复Non-static method cannot be referenced from static content错误

这个错误的根源是:你stream处理的是Object类型的值,直接用Long::longValue(这是Long类的实例方法)编译器不认——它不知道这个Object一定是Long。而且Firestore返回的数值可能是Long或Integer,所以得做安全转型:

修改你的doSumm()方法里的求和逻辑:

// 先定义一个全局Map存每个手机号的总和,方便后续传值
private Map<String, Long> phoneToTotalSum = new HashMap<>();

private void doSumm() {
    Toast.makeText(getApplicationContext(), "Outer Size " + outer.size(), Toast.LENGTH_SHORT).show();
    for (Map.Entry<String, Map<String, Object>> entry : outer.entrySet()) {
        Map<String, Object> innerChapterMap = entry.getValue();
        // 安全转型并求和:兼容Long和Integer类型
        long total = innerChapterMap.values().stream()
            .mapToLong(val -> {
                if (val instanceof Long) {
                    return (Long) val;
                } else if (val instanceof Integer) {
                    return ((Integer) val).longValue();
                }
                return 0; // 遇到非数值类型时的默认值,可根据需求调整
            })
            .sum();
        // 把结果存入全局Map
        phoneToTotalSum.put(entry.getKey(), total);
    }
}

2. 修复外层HashMap的填充逻辑

你现在的代码每次遇到chapter字段都会新建一个inner HashMap并覆盖原来的,导致每个手机号最后只保留一个chapter的值,这完全不符合需求!应该先获取已有的inner Map,再添加新的chapter:

修改Firestore的回调代码:

CollectionReference chemistry = db.collection("RESULTS").document("Summary").collection("ChemistryVII");
chemistry
 .whereEqualTo("school", "Test School")
 .get()
 .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
 @Override
 public void onComplete(@NonNull Task<QuerySnapshot> task) {
     if (!task.isSuccessful()) {
         // 别忘了处理查询失败的情况
         Toast.makeText(getApplicationContext(), "查询失败:" + task.getException().getMessage(), Toast.LENGTH_SHORT).show();
         return;
     }
     outer.clear(); // 先清空旧数据
     for (DocumentSnapshot document : task.getResult()) {
         Map<String, Object> map = document.getData();
         if (map == null) continue; // 处理空文档
         
         // 先获取手机号,做空值判断
         Object phoneObj = map.get("phonenumb");
         if (phoneObj == null) continue;
         String phonenumb = phoneObj.toString();
         
         // 拿到当前手机号对应的inner Map,没有就新建
         Map<String, Object> innerMap = outer.getOrDefault(phonenumb, new HashMap<>());
         
         // 遍历所有chapter字段,加入innerMap
         for (Map.Entry<String, Object> entry : map.entrySet()) {
             // 如果是chapter开头的字段,才加入(比contains更准确)
             if (entry.getKey().startsWith("chapter")) {
                 innerMap.put(entry.getKey(), entry.getValue());
             }
         }
         
         // 把更新后的innerMap放回outer
         outer.put(phonenumb, innerMap);
     }
     // 所有文档处理完再调用求和,不要在循环里重复调用
     doSumm();
     Toast.makeText(getApplicationContext(), "数据处理完成", Toast.LENGTH_SHORT).show();
 }
 });

3. 把求和结果传到图表页面

因为phoneToTotalSumMap<String, Long>,而String和Long都是可序列化的,所以可以用Intent直接传递:

跳转页面时:

// 假设你的图表页面叫ChartDisplayActivity
Intent intent = new Intent(this, ChartDisplayActivity.class);
// 把Map转成Serializable传递
intent.putExtra("PHONE_CHAPTER_SUM", (Serializable) phoneToTotalSum);
startActivity(intent);

在图表页面接收:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_chart_display);
    
    // 获取传递过来的求和Map
    Map<String, Long> sumMap = (Map<String, Long>) getIntent().getSerializableExtra("PHONE_CHAPTER_SUM");
    
    // 接下来就可以用sumMap来生成图表了,比如遍历key和value构建数据集
    if (sumMap != null) {
        for (Map.Entry<String, Long> entry : sumMap.entrySet()) {
            String phone = entry.getKey();
            long total = entry.getValue();
            // 这里添加到图表数据集中
        }
    }
}

额外小建议

  • 不要在Firestore的循环里频繁调用doSumm(),等所有文档都处理完再调用一次,减少不必要的计算。
  • 处理Firestore数据时一定要加空值判断,避免NullPointerException炸锅。
  • 如果chapter字段是固定前缀(比如chapter1、chapter2),用startsWith("chapter")contains("chapter")更准确,防止匹配到类似"xxchapterxx"的意外字段。

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

火山引擎 最新活动