【问题标题】:Firebase "Map while deserializing, but got a class java.util.ArrayList"Firebase“反序列化时映射,但有一个类 java.util.ArrayList”
【发布时间】:2016-11-10 05:54:23
【问题描述】:

我只是在我的项目中试用 Android 上的 Firebase。

我遇到的问题是,每次我拍摄快照并将其“投射”回 POJO 我都会得到这个 -

“反序列化时映射,但得到了一个类java.util.ArrayList”异常。

我一直在环顾四周,甚至使用 HashMap 更改我的所有模型实现,根本没有任何 ArrayList,但仍然得到相同的结果。

这是我的模型:

  public class DevicesController {

        public DevicesCollection devices;
        public int numberOfport;
        String timerStatus;

        public DevicesController(){

            devices = new DevicesCollection();
            timerStatus = "UPDATED";
        }

        public DevicesController(int numberOfport){
            devices = new DevicesCollection();
            this.numberOfport = numberOfport;
            timerStatus = "UPDATED";
        }



        public ArrayList<Integer> getCurrentState(String in){
            ArrayList<Integer> currentState = new ArrayList<Integer>();
            for(int i = 0; i < numberOfport; i++){
                currentState.add(0);
            }
            Iterator it = this.getDevices().getAllDevices().entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry pair = (Map.Entry) it.next();
                Device temp =(Device)pair.getValue();
                if(temp.isOn()){
                    currentState.set(temp.getPort(),1);
                }else if(!temp.isOn()){
                    currentState.set(temp.getPort(),0);
                }
            }

            return currentState;
        }


        public String getStringCurrentState(String in){
            ArrayList<Integer> currentState = getCurrentState("");
            String temp ="";
            for(int i = 0; i < currentState.size();i++){
                temp.concat(""+currentState.get(i));
            }
            return temp;
        }

        public void updateToDb(){
            Global.dbMRoot.child("devicesController").setValue(this);
        }

        public DevicesCollection getDevices() {
            return devices;
        }

        public int getNumberOfport() {
            return numberOfport;
        }

    }

    public class Category {
        public String name;
        public HashMap<String,String> devicesId;
        public DeviceAlarm categoryAlarm;

        public Category(){

        }

        public Category(String name) {
            devicesId = new HashMap<String,String>();
            this.name = name;
        }

        public void addDevice(Device dev){
            devicesId.put(dev.getId(),dev.getId());
        }


        public void removeDevice(Device dev){
            devicesId.remove(dev.getId());
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public HashMap<String,String> getDevicesId() {
            return devicesId;
        }

        public void setDevicesId(HashMap<String,String> devicesId) {
            this.devicesId = devicesId;
        }

    }

public class Device {

    public String id;
    public int port;
    public String name;
    public boolean on;
    public  DeviceAlarm alarm;

    public Device(){

    }


    public Device(String id,String name){
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
        updateToDb();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        updateToDb();
        this.name = name;
    }

    public boolean isOn() {
        return on;
    }

    public void setOn(boolean on) {
        updateToDb();
        this.on = on;
    }

    public void updateToDb(){
        Global.dbMRoot.child("devicesController").child("devices").child("allDevice").child(""+id).setValue(this);
    }
    public DeviceAlarm getTimer() {

        return alarm;
    }


    public int getPort() {

        return port;
    }

    public void setPort(int port) {
        updateToDb();
        this.port = port;
    }

    public DeviceAlarm getAlarm() {
        return alarm;
    }

    public void setAlarm(DeviceAlarm alarm) {
        Global.dbMRoot.child("devicesController").child("timerStatus").setValue("CHANGED");
        this.alarm = alarm;
        updateToDb();
    }

    public void setAlarm(boolean active, Calendar timeOn, Calendar timeOff) {
        Global.dbMRoot.child("devicesController").child("timerStatus").setValue("CHANGED");
        DeviceAlarm temp = new DeviceAlarm();
        temp.setTimeOff(timeOff);
        temp.setTimeOn(timeOn);
        this.alarm = temp;
        updateToDb();
    }
}


package com.lucerna.afgadev.lucerna_maincontroller.Models;

import com.lucerna.afgadev.lucerna_maincontroller.Global;

import java.util.ArrayList;
import java.util.HashMap;

/**
 * Created by aufa on 06/07/2016.
 */
public class DevicesCollection {

    public HashMap<String,Device> allDevices;
    public HashMap<String,Category>  categories;
    int lastId;

    public DevicesCollection(){
        categories = new HashMap<String,Category>();
        lastId = 0;
        allDevices = new HashMap<String, Device>();

    }

    public HashMap<String,Category> getCategories() {
        return categories;
    }

    public HashMap<String,Device> getAllDevices() {
        return allDevices;
    }

    public void addCategory(String name){
        categories.put(name,new Category(name));
    }

    public void removeCategory(String name) throws Exception{
        int index = -1;
        for(int i = 0; i< categories.size(); i++){
            if(categories.get(i).getName().equals(name)){
                index = 1;
            }
        }

        if(index == -1){
            throw new Exception("Category not found");
        }else{
            categories.remove(index);
        }

        updateToDB();

    }

    public void updateToDB(){
        Global.dbMRoot.child("devicesController").child("devices").setValue(this);
    }

    public Category findCategory(String name){
        Category temp = null;
        for(int i = 0; i< this.getCategories().size(); i++){
            if(this.getCategories().get(i).getName().equals(name)){
                temp = this.getCategories().get(i);
            }
        }
        return temp;
    }

    public void switchCategory(String name, boolean on){
        Category cat = findCategory(name);
        for(int i = 0; i < cat.getDevicesId().size();i++){

        }
    }


    public void addDevice(String name, int port){
        Device temp = new Device();
        temp.setPort(port);
        temp.setName(name);
        allDevices.put(""+lastId,temp);
        this.lastId++;
        Global.dbMRoot.child("devicesController").child("devices").child(""+lastId).setValue(allDevices.get(lastId));
    }

    public void removeDevice(int id){
        allDevices.remove(id);
        updateToDB();
    }

    public void setCategoryDevicesAlarm(DeviceAlarm da){

    }

}

示例 JSON 树 GDrive

我仍然不知道它为什么会发生,并且我已经重新检查以确保没有一个是 ArrayList(我知道 firebase 假设支持 arrayList)

感谢所有cmets和答案!

【问题讨论】:

  • 您能否将 minimal JSON(作为文本)包含在您的帖子中,而不是链接到 JSON?如果您稍微减少代码也会有所帮助,因为要解析的内容很多。如果您提供minimal code to reproduce the issue,您将获得最好的帮助。
  • 对不起,代码有点长。我认为主要的一点是对象的所有属性都不是arraylist,所以它很混乱。我将很快用简单的 json 树更新问题,谢谢回复
  • 如果代码很长,请将其减少到仍然重现问题所需的最小值。如果您只对数组列表的行为感兴趣,请仅使用数组列表重现问题。我们需要查看的代码(和关联的 JSON)越小,就越容易为您提供帮助。
  • @Frank:请看我的回答

标签: java android json firebase-realtime-database pojo


【解决方案1】:

我有一个部分答案,但需要 Frank 的专业知识来解释真正发生的事情。

使用版本 9.2.0 运行发布的代码,我发现 allDevicesHashMap 存储为 JSON 数组:

public class DevicesCollection {

    public HashMap<String,Device> allDevices; <-- this is stored as array
    public HashMap<String,Category>  categories;
    int lastId;

这在 Aufa 发布的 JSON 中可见:

{
  "devicesController" : {
    "devices" : {
      "allDevices" : [ { <-- note bracket
        "name" : "",
        "on" : true,
        "port" : 0
      }, {

这似乎是因为allDevices 元素的键是整数形式的字符串。这是在allDevices 的映射中添加条目的代码:

public void addDevice(String name, int port){
    Device temp = new Device();
    temp.setPort(port);
    temp.setName(name);
    allDevices.put(""+lastId,temp); <-- Note that lastId is an integer
    this.lastId++;
    Global.dbMRoot.child("devicesController").child("devices").child(""+lastId).setValue(allDevices.get(lastId));
}

如果这段代码被修改为使用非整数格式的String键,例如:

allDevices.put("ID"+lastId,temp);

然后将地图写成地图,可以使用

getValue(DevicesCollection.class);

【讨论】:

【解决方案2】:

如果你是这样映射的:

    basketRef.addValueEventListener(object : ValueEventListener {
        override fun onDataChange(dataSnapshot: DataSnapshot) {
            if(dataSnapshot.value==null || dataSnapshot.value!!.equals(""))
                Enums.userBasket=UserItem()
            else
                Enums.userBasket = dataSnapshot.getValue(UserItem::class.java)
        }

        override fun onCancelled(p0: DatabaseError) {
            // Failed to read value
            Log.d(TAG, "Error= "+p0.message)
        }

    })

而在 firebase 设备中,ids 元素的子元素像 (-1:"",-2:"")

Firebase Android SDK 发现这是一个 ArrayList 而不是 Map Object。

下面的代码对我来说很好用。我不能使用上面的代码。

Enums.userBasket=UserItem()
    basketRef.addValueEventListener(object : ValueEventListener {
        override fun onDataChange(dataSnapshot: DataSnapshot) {
            if(dataSnapshot.value==null || dataSnapshot.value!!.equals(""))

            else{
                if(dataSnapshot.child("books")!=null){
                    dataSnapshot.child("books").children.forEach {
                        Enums.userBasket!!.books[it.key.toString()] =it.value.toString()
                    }
                }
                if(dataSnapshot.child("cards")!=null){
                    dataSnapshot.child("cards").children.forEach {
                        Enums.userBasket!!.cards[it.key.toString()] =it.value.toString()
                    }
                }
                if(dataSnapshot.child("exams")!=null){
                    dataSnapshot.child("exams").children.forEach {
                        Enums.userBasket!!.exams[it.key.toString()] =it.value.toString()
                    }
                }
            }

        }

        override fun onCancelled(p0: DatabaseError) {
            // Failed to read value
            Log.d(TAG, "Error= "+p0.message)
        }

    })

我的 UserItem 类:

 @IgnoreExtraProperties
data class UserItem(
    var books:MutableMap<String,String> = HashMap(),//id,value
    var cards:MutableMap<String,String> = HashMap(),//id,value
    var exams:MutableMap<String,String> = HashMap()//id,value
)

或者你可以看看这个链接。 Firebase force to use map rather than array

【讨论】:

    【解决方案3】:

    我也遇到了同样的错误。但后来我才知道,起初我在我的Note.kt数据类中使用了tags变量作为List,并将其存储在firestore文档中,但后来我用Map更改了相同的变量名tags并尝试获取来自 Firestore 的数据。在 Firestore 中,我与 List 和 Map 具有相同的名称 tags,因此在从 firestore 获取数据时出现错误。当我删除集合并再次添加数据时,我的问题解决了。

    Note.kt

     data class Note(
     //val tags:List<String>? = null, //first with tags variable 
     val tags:Map<String,Any>? = null, //second with same tags variable
    

    )

    【讨论】:

      猜你喜欢
      • 2017-10-17
      • 1970-01-01
      • 1970-01-01
      • 2020-10-12
      • 2021-08-24
      • 2020-04-04
      • 2021-12-16
      • 2016-12-21
      • 2021-07-08
      相关资源
      最近更新 更多