这是我的代码:
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);
}
但我仍然遇到此异常(:。
任何人都知道为什么吗?
有解决办法吗?
非常感谢您!
答案 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);
}
}
答案 2 :(得分:0)
Kotlin示例
这是从Firebase实时数据库中获取所有嵌套数据的示例。
此示例中有很多标记,每个标记都包含注释列表
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
的
List
的形式存储Map
,索引为键,反序列化时,它将检测到相关的键并将其视为“列表” 因此,具有空值的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();
}
});
享受吧!