Firebase Realtime Database(Android-Java)无参构造已定义仍反序列化报错
问题原因与解答
1. 操作存在的问题
你定义的TestData是DataBaseHelper的非静态内部类,Java中非静态内部类会隐式持有外部类的实例引用,编译器会自动给它的构造方法插入外部类实例的入参,你手写的无参构造实际上运行时是带参的,Firebase反射调用时找不到符合要求的无参构造,就会抛出该异常。
另外还有一个潜在问题:你的phone字段定义为int类型,若手机号长度超过10位会超出int的取值范围(int最大值为2147483647),也可能触发类型转换异常。
2. 多层级JSON的正确解析方式
按照JSON的层级结构定义对应嵌套的实体类即可,规则如下:
- 每一层JSON对象对应一个独立的实体类(或静态内部类)
- 每个实体类必须保留公开无参构造
- 对应层级的字段类型和嵌套类匹配
举个例子,如果你的JSON结构是{"key":"xxx","value":{"name":"xxx","phone":xxx}},就可以定义两层实体类,外层包含String类型的key和内层实体类类型的value字段即可。也可以手动遍历DataSnapshot的child节点逐字段读取,就是你测试成功的那种方式。
3. 实体类变量名与JSON键名的对应规则
默认情况下必须完全一致,包括大小写。如果需要自定义映射,可以在实体类的字段、getter或setter上添加@PropertyName注解,指定对应的JSON键名即可,示例:
@PropertyName("user_phone") public long phone;
解决方案
你只需要做一处修改就能解决直接映射实体类失败的问题:把TestData改成静态内部类,或者将其单独提取为独立的Java类。
修改后的代码示例:
public class DataBaseHelper { private DatabaseReference mDatabase; public TestData result; public DataBaseHelper() { mDatabase = FirebaseDatabase.getInstance().getReference(); Query query = mDatabase.child("TestData"); query.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { for (DataSnapshot userSnapshot : dataSnapshot.getChildren()) { try { Log.w("datosdb", userSnapshot.toString()); result = userSnapshot.getValue(TestData.class); } catch (Exception e) { Log.w("datosdb", "解析失败", e); } } } @Override public void onCancelled(DatabaseError databaseError) { Log.w("datosdb", "loadPost:onCancelled", databaseError.toException()); } }); } // 加static修饰改为静态内部类 public static class TestData { public TestData() { } public String name; // 把int改成long避免数值溢出 public long phone; public String getName() { return this.name; } public long getPhone() { return this.phone; } } }
如果你开启了ProGuard,还需要在ProGuard规则中添加如下配置,避免实体类的构造和成员被混淆移除:
-keep class com.example.purinasa.application.dataBase.DataBaseHelper$TestData { *; }
内容的提问来源于stack exchange,提问作者Iroqas
相关产品推荐
相关产品推荐

