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

Firebase Realtime Database无需HashMap实现实体类字段映射读取

问题描述

我通过带构造函数的类向Firebase Realtime Database写入数据,但读取时文档说明使用自定义类需要为每个元素创建HashMap。由于要写入255条以上的数据,我定义了User和User1两个类,每个类都编写HashMap过于繁琐。想请教两个问题:

  1. 如何让数据库变量名与类中变量名一致(例如类中int b = 0对应数据库中b: 0)
  2. 无需HashMap,怎么读取数据库中每个变量的值

写入数据代码

if (user != null) {
    if(database.child(getEmail)==null) {
        User newUser = new User(getEmail, coins, ....);
        User1 newUser1 = new User1(a256, a257, ....);
        database.child(getEmail).push().setValue(newUser1);
        database.child(getEmail).push().setValue(newUser);
    }
}

读取数据代码

ValueEventListener valueEventListener = new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot snapshot) {
        for(DataSnapshot ds : snapshot.getChildren()){
            User user = ds.getValue(User.class);
            //将读取的数据库信息保存到SharedPreferences
            PreferenceConfig.GetEmail(getApplicationContext(), getEmail);
            PreferenceConfig.GetCoin(getApplicationContext(), getEmail);
            PreferenceConfig.GetA256(getApplicationContext(), a256);
            ...
        }
    }
};
database.addValueEventListener(valueEventListener);

数据库JSON结构

{
  "User": {
    "mail@gmail:com": {
      "-NHTVinbEVUAqJwK8Umt": {
        "getEmail": "mail@gmail.com",
        "coins": 100,
        .....
      },
      "-NHTVinpCPOJ4UPZvgpN": {
        "a256":0,
        "a257":0
          ...............
      }
    }
  }
}

解决方案

一、实现数据库变量名与类变量名一致

Firebase Realtime Database的Java SDK默认支持自动映射,不需要手动写HashMap,只要遵循以下规则:

  • 类必须包含无参构造函数:SDK通过反射实例化类时必须用到,哪怕是空实现也得写
  • 字段设置为public,或提供标准getter方法:
    • 若字段是public int coins;,数据库键名自动对应coins
    • 若字段是私有,写public int getCoins(),SDK会自动去掉get前缀并将首字母小写,对应数据库键coins
  • 避免冗余命名:比如你代码里的getEmail字段,数据库会生成同名键;如果想让数据库键是email,直接把字段改成public String email;即可

以User类为例,正确的定义方式:

public class User {
    // 公共字段,直接映射数据库同名键
    public String getEmail;
    public int coins;
    // 其他字段...

    // 必须存在的无参构造
    public User() {}

    // 带参构造,用于写入数据时初始化
    public User(String getEmail, int coins, ...) {
        this.getEmail = getEmail;
        this.coins = coins;
        // 初始化其他字段
    }
}

User1类按照同样规则定义即可。

二、无需HashMap直接读取数据

只要类符合上面的规则,直接用ds.getValue(YourClass.class)就能完成自动映射,无需HashMap。针对你的代码,需要调整读取逻辑:

优化读取逻辑

因为你在同一个节点下push了User和User1两种对象,读取时需要判断当前节点对应的类类型:

ValueEventListener valueEventListener = new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot snapshot) {
        for(DataSnapshot ds : snapshot.getChildren()){
            // 先尝试解析为User类
            User user = ds.getValue(User.class);
            if (user != null && user.getEmail != null) {
                // 保存User类字段到SharedPreferences
                PreferenceConfig.GetEmail(getApplicationContext(), user.getEmail);
                PreferenceConfig.GetCoin(getApplicationContext(), user.coins);
                continue;
            }
            // 再尝试解析为User1类
            User1 user1 = ds.getValue(User1.class);
            if (user1 != null) {
                // 保存User1类字段
                PreferenceConfig.GetA256(getApplicationContext(), user1.a256);
                PreferenceConfig.GetA257(getApplicationContext(), user1.a257);
                // 处理其他字段...
            }
        }
    }
};
database.addValueEventListener(valueEventListener);

可选:优化写入逻辑

你代码里database.child(getEmail)==null的判断无效,Firebase的child()方法永远不会返回null,判断节点是否存在应该用exists()或异步监听。另外,push()会生成随机ID,如果你想区分User和User1的数据,建议用固定键名存储,避免循环判断类型:

if (user != null) {
    DatabaseReference userRef = database.child(getEmail);
    userRef.child("basicInfo").setValue(new User(getEmail, coins, ...));
    userRef.child("extendedInfo").setValue(new User1(a256, a257, ...));
}

这样读取时可以直接定位到basicInfo和extendedInfo节点,逻辑更清晰高效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 10:40:31