DatabaseException:无法将java.lang.String类型的对象转换为type

我已经查看了类似问题的其他一些答案,但不明白为什么我的工作不起作用。

我正在尝试让我的应用程序从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; } } 

我也尝试过使用值事件监听器,但是出现了同样的问题。

您收到此错误:

 Can't convert object of type java.lang.String to type com.parrot.sdksample.activity.CommandObject 

因为您正在尝试读取类型为String的类型为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); 

而这种方法使用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); 

在这两种情况下,您的输出将是:

 false / TAKE_OFF / 1.512686825309134E9 false / LAND / 1.512687248764272E9 

Alex提供的解决方案有效,但没有完全回答为什么我无法将数据存储在对象中,而在我的应用程序中,当孩子添加了监听器时,该应用程序能够读取Firebase上已有的数据但是新的添加了child,值为空。

  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(); } } } 

Alex为我发布了正确的解决方案,但由于我使用的是firebase-ui和kotlin,因此使用的代码不同。 更多信息在这里

  val options = FirebaseRecyclerOptions.Builder() .setQuery(query, ChatMessage::class.java) .build() // equivalent options object with manual parsing, use it to debug which field gives error val options = FirebaseRecyclerOptions.Builder() .setQuery(query, object : SnapshotParser { 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(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) } }