我已经针对类似的问题看了几个其他答案,但不明白为什么我的工作没有。
我试图让我的应用程序从Firebase读取命令并移动无人机。 firebase中的命令来自一个单独的软件。该应用程序构建在Parrot Drone SDK示例代码之上。
它似乎能够从命令对象获取文本并将其附加到textview,但是当添加新子项时它只会崩溃。我在添加新孩子时收到此错误。
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.parrot.sdksample, PID: 10592
com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type com.parrot.sdksample.activity.CommandObject
at com.google.android.gms.internal.zg.zzb(Unknown Source)
at com.google.android.gms.internal.zg.zza(Unknown Source)
at com.google.firebase.database.DataSnapshot.getValue(Unknown Source)
at com.parrot.sdksample.activity.MiniDroneActivity$13.onChildAdded(MiniDroneActivity.java:383)
at com.google.android.gms.internal.px.zza(Unknown Source)
at com.google.android.gms.internal.vj.zzHX(Unknown Source)
at com.google.android.gms.internal.vp.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
我在firebase中的数据结构示例如下。
{
"drones" : {
"commands" : {
"-L-n9HwaQktOdI2VEVlH" : {
"executed" : false,
"text" : "TAKE_OFF",
"timestamp" : 1.512686825309134E9
},
"-L-nAuK5Ifde7Cdnan8K" : {
"executed" : false,
"text" : "LAND",
"timestamp" : 1.512687248764272E9
}
}
}
}
我的活动中从firebase获取数据的函数如下所示。
private void initFirebase(){
mCommandTextView = (TextView) findViewById(R.id.commandTextView);
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference commandsRef = database.getReference("drones/commands");
ChildEventListener childEventListener = new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());
CommandObject command = dataSnapshot.getValue(CommandObject.class);
mCommandTextView.append(command.text + "\n");
// I've tried commenting out the if statements below this, but it doesn't seem to make a difference.
if ("TAKE_OFF".equals(command.text)) {
mMiniDrone.takeOff();
} else if ("LAND".equals(command.text)) {
mMiniDrone.land();
}
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName){
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName){
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
};
commandsRef.addChildEventListener(childEventListener);
}
我的CommandObject类看起来像这样。
public class CommandObject {
public String text;
public float timestamp;
public boolean executed;
public CommandObject() {
}
public CommandObject(boolean executed, String text, float timestamp){
this.executed = executed;
this.text = text;
this.timestamp = timestamp;
}
}
我也尝试过使用值事件侦听器,但发生了同样的问题。
答案 0 :(得分:6)
您收到此错误:
Can't convert object of type java.lang.String to type com.parrot.sdksample.activity.CommandObject
因为您正在尝试读取类型为String
的{{1}}类型的数据以及您收到此错误的原因。
获取这些值的更简单方法是使用CommandObject
类,如下所示:
String
这是使用DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference commandsRef = rootRef.child("drones").child("commands");
ValueEventListener eventListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
boolean executed = ds.child("executed").getValue(Boolean.class);
String text = ds.child("text").getValue(String.class);
double timestamp = ds.child("timestamp").getValue(Double.class);
Log.d("TAG", executed + " / " + text + " / " + timestamp);
}
}
@Override
public void onCancelled(DatabaseError databaseError) {}
};
commandsRef.addListenerForSingleValueEvent(eventListener);
class:
CommandObject
在这两种情况下,您的输出将是:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference commandsRef = rootRef.child("drones").child("commands");
ValueEventListener eventListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
CommandObject commandObject = ds.getValue(CommandObject.class);
Log.d("TAG", commandObject.getExecuted() + " / " +
commandObject.getText() + " / " +
commandObject.getTimestamp());
}
}
@Override
public void onCancelled(DatabaseError databaseError) {}
};
commandsRef.addListenerForSingleValueEvent(eventListener);
答案 1 :(得分:3)
Alex提供的解决方案有效,但没有完全回答为什么我无法将数据存储在对象中,而对于我的应用程序,当孩子添加了监听器时,应用程序能够读取数据已经在Firebase上,但是当添加新子项时,该值为空。
onChildAdded:DataSnapshot { key = -L0JjGo-3QMYDsuTMQcN, value = }
我已经做了一点挖掘,找出可能导致这种情况的原因,并发现它可能是因为这些值并非都是同时写的。看着firebase似乎首先添加了密钥,然后添加了值。这就是错误说无法转换的原因,这是因为它不存在。 我使用Python Firebase Admin SDK将数据添加到Firebase,因此我不确定这是否是原因。
因此,为了解决我的问题,我将代码移动到onChildChanged函数并添加了一个检查,以便代码仅在我需要的所有数据都存在时运行。这样我就可以直接获得存储在对象中的值。
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName){
if (dataSnapshot.child("text").exists() &&
dataSnapshot.child("executed").exists() &&
dataSnapshot.child("timestamp").exists()){
Log.d(TAG, "onChildChanged:" + dataSnapshot.toString());
CommandObject command = dataSnapshot.getValue(CommandObject.class);
if ("TAKE_OFF".equals(command.text)) {
mMiniDrone.takeOff();
} else if ("LAND".equals(command.text)) {
mMiniDrone.land();
}
}
}
答案 2 :(得分:1)
Alex为我发布了正确的解决方案,但由于我使用的是firebase-ui和kotlin,因此使用的代码不同。更多信息here
val options = FirebaseRecyclerOptions.Builder<ChatMessage>()
.setQuery(query, ChatMessage::class.java)
.build()
// equivalent options object with manual parsing, use it to debug which field gives error
val options = FirebaseRecyclerOptions.Builder<ChatMessage>()
.setQuery(query, object : SnapshotParser<ChatMessage> {
override fun parseSnapshot(snapshot: DataSnapshot): ChatMessage {
val senderId = snapshot.child("senderId").getValue(String::class.java)
val receiverId = snapshot.child("receiverId").getValue(String::class.java)
val senderName = snapshot.child("senderName").getValue(String::class.java)
val text = snapshot.child("text").getValue(String::class.java)
val timestamp = snapshot.child("timestamp").getValue(Long::class.java)
return ChatMessage(senderId, receiverId, senderName, text, timestamp)
}
})
.build()
adapterMessages = object : FirebaseRecyclerAdapter<ChatMessage, ChatHolder>(options) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChatHolder {
val rootView = LayoutInflater.from(parent.context).inflate(R.layout.chat_message_item, parent, false)
return ChatHolder(rootView)
}
override fun onBindViewHolder(holder: ChatHolder, position: Int, model: ChatMessage) {
holder.populateItem(model)
}
}
答案 3 :(得分:0)
我遇到了类似的问题,无法从数据库中检索数据。邮件中出现DatabaseException
错误
无法从此类型转换为该类型。
我犯的错误是我不正确地写入数据库。我写了类似...
mdatabaseReference.setValue(myObject)
代替
mdatabaseReference.child(myObject.getId()).setValue(myObject)
所以从本质上讲,我建议的答案是:您应该确保将数据正确写入JSON树中正确节点的数据库中,否则,当您从数据库中读取数据时,很可能会遇到这种错误。
答案 4 :(得分:0)
您可以像这样正常使用构造函数oop
相同并且没有错误
CommandObject command = new CommandObject(ds.child("").getValue()....
填写并确保您在Firebase数据中的引用不为空
答案 5 :(得分:0)
在我的情况下,问题是我使用的是Kotlin类,并且没有默认构造函数,例如
constructor() : this(0, "")
答案 6 :(得分:0)
如果您正在数据库中使用map对象,则应直接对对象使用get方法
doc: DocumentSnapshot
val data = doc.get("location", SaleLocations::class.java)