Andorid在反序列化时期望List,但是得到了一个类java.util.HashMap

时间:2018-07-17 11:16:56

标签: java android firebase firebase-realtime-database

我想从Android中的Firebase获取所有餐厅列表。 my database

这是我的代码:

boolean delivery;
String openTime, closeTime, restaurantName;
long likes;
List<String> utilities;

List<RestaurantModel> listRes;

DatabaseReference dataResReference;

public RestaurantModel(){
    dataResReference = FirebaseDatabase.getInstance().getReference().child("restaurants");
}

public List<RestaurantModel> getallRestaurant(){

    listRes = new ArrayList<>();
    ValueEventListener valueEventListener = new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                for (DataSnapshot dataValues : dataSnapshot.getChildren()){
                    RestaurantModel restaurantModel = dataValues.getValue(RestaurantModel.class);
                    listRes.add(restaurantModel);
                }
        }

        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {

        }
    };
    dataResReference.addListenerForSingleValueEvent(valueEventListener);
    return  listRes;
}

但是我有例外

Expected a List while deserializing, but got a class java.util.HashMap

在RestaurantModel restaurantModel = dataValues.getValue(RestaurantModel.class);

更新: 基于Alex Mamo answser,我更改了代码:

public void getAllRestaurant(final WhereInterface whereInterface){
    ValueEventListener valueEventListener = new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            //go to node restaurant because datasnapshot is parent node
            DataSnapshot dataSnapshotRes = dataSnapshot.child("restaurants");
            //

            for (DataSnapshot valueRes : dataSnapshotRes.getChildren()){
                RestaurantModel restaurantModel = valueRes.getValue(RestaurantModel.class);
                whereInterface.getAllRestaurantModel(restaurantModel);

            }
        }

        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {

        }
    };
    databaseReferenceRoot.addListenerForSingleValueEvent(valueEventListener);
}

但我仍然遇到此异常(:。

任何人都知道为什么吗?

有解决办法吗?

非常感谢您!

5 个答案:

答案 0 :(得分:2)

您的代码中有两个问题。第一个是该错误:

Expected a List while deserializing, but got a class java.util.HashMap

可以使用以下几行代码解决:

ValueEventListener valueEventListener = new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
        List<RestaurantModel> listRes = new ArrayList<>();

        for (DataSnapshot dataValues : dataSnapshot.getChildren()){
            RestaurantModel restaurantModel = dataValues.getValue(RestaurantModel.class);
            listRes.add(restaurantModel);
        }

        //Do what you need to do with listRes
    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {
        throw databaseError.toException(); //Don't ignore errors
    }
};
dataResReference.addListenerForSingleValueEvent(valueEventListener);

第二个问题是您现在无法返回尚未加载的内容。 Firebase API是asynchronous,这意味着onDataChange()方法在调用后立即返回,并且它返回的Task中的回调将在一段时间后调用。无法保证需要多长时间。因此,可能需要几百毫秒到几秒钟的时间才能获得该数据。由于该方法会立即返回,因此由于该方法的异步行为,您尝试返回的listRes列表将为空。

基本上,您正在尝试从异步的API同步返回值。那不是一个好主意。您应该按预期异步处理API。

此问题的快速解决方案是仅在listRes方法内使用onDataChange()列表(如上述代码行中所述),否则,建议您查看anwser的最后一部分从这个 post 中,我已经解释了如何使用自定义回调来完成。您也可以查看此 video 以获得更好的理解。

编辑:

public void getAllRestaurant(){
    ValueEventListener valueEventListener = new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            List<RestaurantModel> listRestaurant = new ArrayList<>();

            for (DataSnapshot valueRes : dataSnapshot.getChildren()){
                RestaurantModel restaurantModel = valueRes.getValue(RestaurantModel.class);
                Log.d("Test", restaurantModel.getRestaurantName());
                listRestaurant.add(restaurantModel);
            }

            //Do what you need to do with listRes
        }

        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {
            throw databaseError.toException();
        }
    };
    DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();        
    rootRef.child("restaurants").addListenerForSingleValueEvent(valueEventListener);
}

答案 1 :(得分:1)

我知道这可能为时已晚,但是我希望我的回答可以对某人有所帮助。我知道两种解决此问题的方法。一旦有时间,我将更新答案。

#解决方案1 ​​

首先,我复制并粘贴您的代码。我不清楚您是如何将数据添加到Firebase的,但是我觉得您是直接将数据添加到Firebase的。

这是我的MainActivity代码:

public class MainActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        RestaurantModel rm;
        List<String> utils;

        //restaurant 1
        rm = new RestaurantModel();
        rm.closeTime = "12:00am";
        rm.openTime = "12:00pm";
        rm.delivery = true;
        rm.likes = 300;
        rm.restaurantName = "KFC";
        utils = new ArrayList<>();
        utils.add("free wifi");
        utils.add("free Parking");
        utils.add("free water");
        rm.utilities = utils;

        //write first restaurant to Firebase
        rm.addRestaurantToFirebase(rm);


        //restaurant 2
        rm = new RestaurantModel();
        rm.closeTime = "5:00am";
        rm.openTime = "12:00pm";
        rm.delivery = false;
        rm.likes = 500;
        rm.restaurantName = "SubWay";
        utils = new ArrayList<>();
        utils.add("free wifi");
        utils.add("free Parking");

        rm.utilities = utils;

        //write Second restaurant to Firebase
        rm.addRestaurantToFirebase(rm);


        rm.getallRestaurant();

    }

}

这是RestaurantModel

public class RestaurantModel {
    public boolean delivery;
    public String openTime;
    public String closeTime;
    public String restaurantName;
    public long likes;
    public List<String> utilities;


    public List<RestaurantModel> listRes;

    DatabaseReference dataResReference;

    public RestaurantModel() {
        dataResReference = FirebaseDatabase.getInstance().getReference().child("restaurants");
    }

    public List<RestaurantModel> getallRestaurant() {
        listRes = new ArrayList<>();

        ValueEventListener valueEventListener = new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                for (DataSnapshot dataValues : dataSnapshot.getChildren()) {
                    RestaurantModel restaurantModel = dataValues.getValue(RestaurantModel.class);
                    listRes.add(restaurantModel);

                    Log.d("restaurantModel", restaurantModel.restaurantName);
                }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        };
        dataResReference.addListenerForSingleValueEvent(valueEventListener);
        return listRes;
    }


    public void addRestaurantToFirebase(RestaurantModel rm) {
        dataResReference.child(restaurantName).setValue(rm);
    }

}

here the result in firebase

答案 2 :(得分:0)

Kotlin示例
这是从Firebase实时数据库中获取所有嵌套数据的示例。

此示例中有很多标记,每个标记都包含注释列表

enter image description here

df <- data.frame(
  A= c("A1", "A1", "B2", "B3", "B3"),
  B = c(2001,2005,2010,2001,2005)
)

library(dplyr)

df %>% group_by(A) %>% 
  summarise(count = n(), year = paste(B, collapse = ","))

答案 3 :(得分:0)

我不确定是否是这种情况,但可能会帮助其他人:请勿将null的存储在List

  1. Firebase以索引List的形式存储Map,索引为键,反序列化时,它将检测到相关的键并将其视为“列表”
  2. 不存储空值,null删除字段

因此,具有空值的List不会具有所有索引,并且在解析后,Firebase认为它是Map

存储某种“空”值而不是null即可。

旁注:如果您的map具有相关索引,则会发生类似的错误,只需在键上添加一些非数字前缀即可。

答案 4 :(得分:0)

先决条件:我们正在为我们的模型类对象设置 Snapshot 响应。

在我们的模型类中。必须有一个或多个我们设置为列表的对象。

现在作为响应,Snapshot 中的 ArrayList 作为 hashmap 出现在我们面前,但我们需要列表。

所以我找到的解决方案是:

将第一层数据设置为模型对象,因为它使用有限参数构造函数。

然后是 ArrayList 对象 - 将其作为该特定类的单独对象获取,然后通过 getter 将其添加到模型类中。

遵循以下代码示例。

假设您有对象模型类。和 InterList 作为数组列表。我的解决方案是将innerList作为一个单独的对象,然后使用构造函数将其添加到模型类中。

如果此列表未响应。您可以使用有限的构造函数参数来处理它们。

    Object object;
    FirebaseDatabase.getInstance().getReference().getRoot().child("yourKey").addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot snapshot) {
            for (DataSnapshot temp : snapshot.getChildren()) {

                if (temp.hasChild("InnerList")) {
                    List<InnerList> innerList = new ArrayList<InnerList>();
                    DataSnapshot yourInnerArrayListSnapShot = temp.child("InnerList");

                    for (DataSnapshot innerTemp : yourInnerArrayListSnapShot.getChildren()) {
                        InnerList yourInnerArrayListObject = innerTemp.getValue(InnerList.class);
                        innerList.add(yourInnerArrayListObject);
                    }
                    
                    object = new Object(a, b, innerList);
                } else {
                    object = new Object(a, b);
                }
            }

        }

        @Override
        public void onCancelled(@NonNull DatabaseError error) {
            Log.d(TAG, "onCancelled error is : " + error.getMessage());
            pd.dismiss();
        }
    });

享受吧!