如果对象包含列表,我如何从 Firebase 实时数据库中检索对象?
How can I retrieve an object from the Firebase RealTime Database if it contains a List?
我正在尝试学习如何使用 Firebase,并决定制作一个使用 Firebase 实时数据库的简单 android 应用程序。游戏需要主持大厅的主机,以及可以加入该大厅的玩家。我做了一个主机class,有一堆数据类型,其中有一个列表(游戏涉及使用主机给玩家的提示)。当我尝试从数据库中读取时,我 运行 遇到了问题。
我的大厅是一个列表视图,我想用数据库中的主机列表填充它,但是当我尝试从中读取时,我得到了这个讨厌的错误:
com.google.firebase.database.DatabaseException: Class java.util.List has generic type parameters, please use GenericTypeIndicator instead
我知道还有其他关于同一错误的问题,但我无法成功应用这些答案。我是 android 开发的新手,非常感谢任何帮助。
这里是我的用户自定义class:
public class HostPlayer {
private String hostName;
private String photoUrl;
private String primaryHint;
List<String> hints = new ArrayList<String>();
private int numHints;
private int numTime;
private boolean inProgress = false;
public HostPlayer() {
}
public HostPlayer(String hostName, int numHints, int numTime, List<String> hints, String primaryHint, String photoUrl) {
this.hostName = hostName;
this.numHints = numHints;
this.numTime = numTime;
this.hints = hints;
this.primaryHint = primaryHint;
this.photoUrl = photoUrl;
this.inProgress = false;
}
public void setPhotoUrl(String photoUrl) {this.photoUrl = photoUrl;}
public void setPrimaryHint(String primaryHint) {this.primaryHint = primaryHint;}
public void setHints(List hints) {this.hints = hints;}
public String getHostName() {return this.hostName;}
public int getNumHints() {return this.numHints;}
public int getNumTime() {return this.numTime;}
public String getPrimaryHint() {return this.primaryHint;}
public List getHints() {return this.hints;}
public void setInProgress() {this.inProgress = true;}
public boolean getInProgress() {return this.inProgress;}
}
这是我从数据库读取的代码:
public class JoinGame extends AppCompatActivity {
ListView lv;
private FirebaseDatabase pFireBaseDatabase;
private DatabaseReference pDatabaseReference;
private ChildEventListener pChildEventListener;
List<HostPlayer> hostPlayerList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_join_game);
pFireBaseDatabase = FirebaseDatabase.getInstance();
pDatabaseReference = pFireBaseDatabase.getReference().child("hosts");
pChildEventListener = new ChildEventListener() {
@Override
public void onChildAdded(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {
HostPlayer hostPlayer = snapshot.getValue(HostPlayer.class); //this is where the error happens
hostPlayerList.add(hostPlayer);
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
}
};
pDatabaseReference.addChildEventListener(pChildEventListener);
lv = findViewById(R.id.listView_hosts);
ArrayAdapter<HostPlayer> hostPlayerArrayAdapter = new ArrayAdapter<HostPlayer>(
this, android.R.layout.simple_list_item_1, hostPlayerList
);//making an arrayAdapter out of the list of HostPlayer objects
lv.setAdapter(hostPlayerArrayAdapter);
}
}
数据库 JSON 的结构如下:
{
"hosts" : {
"some-data-key" : {
"hints" : [ "first hint", "second hint" ],
"hostName" : "mom",
"inProgress" : false,
"numHints" : 3,
"numTime" : 30,
"primaryHint" : "Living Room"
}
},
"players" : {
"another-data-key" : {
"hostName" : "firstName",
"inProgress" : false,
"numHints" : 0,
"numTime" : 0
}
}
}
我知道是列表“提示”导致了这个错误,但仍然不明白为什么以及如何修复它。我将不胜感激任何解释 and/or 解决方案。感谢您的时间和帮助。
编辑:我忘了粘贴 logcat,这里是:
2021-10-23 16:11:20.732 21137-21137/com.example.treasurehunt E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.treasurehunt, PID: 21137
com.google.firebase.database.DatabaseException: Class java.util.List has generic type parameters, please use GenericTypeIndicator instead
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.deserializeToClass(CustomClassMapper.java:224)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.deserializeToType(CustomClassMapper.java:179)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.access0(CustomClassMapper.java:48)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper$BeanMapper.deserialize(CustomClassMapper.java:593)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper$BeanMapper.deserialize(CustomClassMapper.java:563)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertBean(CustomClassMapper.java:433)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.deserializeToClass(CustomClassMapper.java:232)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertToCustomClass(CustomClassMapper.java:80)
at com.google.firebase.database.DataSnapshot.getValue(DataSnapshot.java:203)
at com.example.treasurehunt.JoinGame.onChildAdded(JoinGame.java:41)
at com.google.firebase.database.core.ChildEventRegistration.fireEvent(ChildEventRegistration.java:79)
at com.google.firebase.database.core.view.DataEvent.fire(DataEvent.java:63)
at com.google.firebase.database.core.view.EventRaiser.run(EventRaiser.java:55)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
我已经改编了 Frank 和 Alex 在他们的评论中提到的答案。它似乎适用于您的情况。而不是直接使用
snapshot.getValue(HostPlayer.class);
像这样使用 GenericTypeIndicator;
pChildEventListener = new ChildEventListener() {
@Override
public void onChildAdded(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {
GenericTypeIndicator<HostPlayer> t = new GenericTypeIndicator<HostPlayer>() {};
HostPlayer hostPlayer = snapshot.getValue(t);//I was able to get the list without an error
...
}
...
};
我正在尝试学习如何使用 Firebase,并决定制作一个使用 Firebase 实时数据库的简单 android 应用程序。游戏需要主持大厅的主机,以及可以加入该大厅的玩家。我做了一个主机class,有一堆数据类型,其中有一个列表(游戏涉及使用主机给玩家的提示)。当我尝试从数据库中读取时,我 运行 遇到了问题。
我的大厅是一个列表视图,我想用数据库中的主机列表填充它,但是当我尝试从中读取时,我得到了这个讨厌的错误:
com.google.firebase.database.DatabaseException: Class java.util.List has generic type parameters, please use GenericTypeIndicator instead
我知道还有其他关于同一错误的问题,但我无法成功应用这些答案。我是 android 开发的新手,非常感谢任何帮助。
这里是我的用户自定义class:
public class HostPlayer {
private String hostName;
private String photoUrl;
private String primaryHint;
List<String> hints = new ArrayList<String>();
private int numHints;
private int numTime;
private boolean inProgress = false;
public HostPlayer() {
}
public HostPlayer(String hostName, int numHints, int numTime, List<String> hints, String primaryHint, String photoUrl) {
this.hostName = hostName;
this.numHints = numHints;
this.numTime = numTime;
this.hints = hints;
this.primaryHint = primaryHint;
this.photoUrl = photoUrl;
this.inProgress = false;
}
public void setPhotoUrl(String photoUrl) {this.photoUrl = photoUrl;}
public void setPrimaryHint(String primaryHint) {this.primaryHint = primaryHint;}
public void setHints(List hints) {this.hints = hints;}
public String getHostName() {return this.hostName;}
public int getNumHints() {return this.numHints;}
public int getNumTime() {return this.numTime;}
public String getPrimaryHint() {return this.primaryHint;}
public List getHints() {return this.hints;}
public void setInProgress() {this.inProgress = true;}
public boolean getInProgress() {return this.inProgress;}
}
这是我从数据库读取的代码:
public class JoinGame extends AppCompatActivity {
ListView lv;
private FirebaseDatabase pFireBaseDatabase;
private DatabaseReference pDatabaseReference;
private ChildEventListener pChildEventListener;
List<HostPlayer> hostPlayerList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_join_game);
pFireBaseDatabase = FirebaseDatabase.getInstance();
pDatabaseReference = pFireBaseDatabase.getReference().child("hosts");
pChildEventListener = new ChildEventListener() {
@Override
public void onChildAdded(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {
HostPlayer hostPlayer = snapshot.getValue(HostPlayer.class); //this is where the error happens
hostPlayerList.add(hostPlayer);
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
}
};
pDatabaseReference.addChildEventListener(pChildEventListener);
lv = findViewById(R.id.listView_hosts);
ArrayAdapter<HostPlayer> hostPlayerArrayAdapter = new ArrayAdapter<HostPlayer>(
this, android.R.layout.simple_list_item_1, hostPlayerList
);//making an arrayAdapter out of the list of HostPlayer objects
lv.setAdapter(hostPlayerArrayAdapter);
}
}
数据库 JSON 的结构如下:
{
"hosts" : {
"some-data-key" : {
"hints" : [ "first hint", "second hint" ],
"hostName" : "mom",
"inProgress" : false,
"numHints" : 3,
"numTime" : 30,
"primaryHint" : "Living Room"
}
},
"players" : {
"another-data-key" : {
"hostName" : "firstName",
"inProgress" : false,
"numHints" : 0,
"numTime" : 0
}
}
}
我知道是列表“提示”导致了这个错误,但仍然不明白为什么以及如何修复它。我将不胜感激任何解释 and/or 解决方案。感谢您的时间和帮助。
编辑:我忘了粘贴 logcat,这里是:
2021-10-23 16:11:20.732 21137-21137/com.example.treasurehunt E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.treasurehunt, PID: 21137
com.google.firebase.database.DatabaseException: Class java.util.List has generic type parameters, please use GenericTypeIndicator instead
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.deserializeToClass(CustomClassMapper.java:224)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.deserializeToType(CustomClassMapper.java:179)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.access0(CustomClassMapper.java:48)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper$BeanMapper.deserialize(CustomClassMapper.java:593)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper$BeanMapper.deserialize(CustomClassMapper.java:563)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertBean(CustomClassMapper.java:433)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.deserializeToClass(CustomClassMapper.java:232)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertToCustomClass(CustomClassMapper.java:80)
at com.google.firebase.database.DataSnapshot.getValue(DataSnapshot.java:203)
at com.example.treasurehunt.JoinGame.onChildAdded(JoinGame.java:41)
at com.google.firebase.database.core.ChildEventRegistration.fireEvent(ChildEventRegistration.java:79)
at com.google.firebase.database.core.view.DataEvent.fire(DataEvent.java:63)
at com.google.firebase.database.core.view.EventRaiser.run(EventRaiser.java:55)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
我已经改编了 Frank 和 Alex 在他们的评论中提到的答案。它似乎适用于您的情况。而不是直接使用
snapshot.getValue(HostPlayer.class);
像这样使用 GenericTypeIndicator;
pChildEventListener = new ChildEventListener() {
@Override
public void onChildAdded(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {
GenericTypeIndicator<HostPlayer> t = new GenericTypeIndicator<HostPlayer>() {};
HostPlayer hostPlayer = snapshot.getValue(t);//I was able to get the list without an error
...
}
...
};