【问题标题】:DatabaseException: Can't convert object of type java.lang.String to typeDatabaseException:无法将 java.lang.String 类型的对象转换为类型
【发布时间】:2018-05-22 04:17:11
【问题描述】:

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

我正在尝试让我的应用从 Firebase 读取命令并移动无人机。 firebase 中的命令来自一个单独的软件。该应用基于 Parrot Drone SDK 示例代码构建。

它似乎能够从命令对象中获取文本并将其附加到文本视图,但是当添加一个新子对象时,它就会崩溃。添加新孩子时出现此错误。

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

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

【问题讨论】:

  • 乍一看,代码和您共享的 JSON 匹配。您确定在/drones/commands 下没有其他格式的孩子吗?
  • 是的,json 是从 firebase 的根目录导出的。

标签: java android firebase firebase-realtime-database


【解决方案1】:

如果您在数据库中使用地图对象,则应直接对您的对象使用 get 方法

doc: DocumentSnapshot val data = doc.get("location", SaleLocations::class.java)

【讨论】:

    【解决方案2】:

    在我的情况下,问题是我使用 Kotlin 类,并且没有默认构造函数,例如

     constructor() : this(0, "")
    

    【讨论】:

      【解决方案3】:

      你可以像这样正常使用构造函数oop

      还是一样,没有错误了

      CommandObject command = new CommandObject(ds.child("").getValue()....
      

      填写并确保您在 Firebase 数据中的引用不应为空

      【讨论】:

        【解决方案4】:

        我遇到了一个类似的问题,我无法从数据库中检索数据;出现DatabaseException 错误消息

        无法从这种类型转换为那种类型。

        我犯的错误是我错误地写入数据库。我写了类似...

        mdatabaseReference.setValue(myObject)
        

        而不是

        mdatabaseReference.child(myObject.getId()).setValue(myObject)
        

        所以基本上我建议的答案是:你应该确保你的数据被正确地写入到 JSON 树中正确节点的数据库中,否则你在从数据库中读取时可能会遇到这种错误。

        【讨论】:

        • @Desmond chin 应该也分享了他写入数据库的代码,这样我们就可以检查以确保他在写入数据库时​​没有犯这种错误。
        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

          您收到此错误:

          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
          

          【讨论】:

            【解决方案7】:

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

            【讨论】:

            • 我没有在你的问题中看到你想从对象中获取数据。我相应地更新了我的答案。您在回答中所说的“是因为这些值不是同时写入的”。它is incorrect。您收到该错误是因为您试图读取 String 类型的数据,该数据类型为 CommandObject,这就是您收到该错误的原因。这是唯一的原因,这就是我为您提供答案并使用 String 类的原因。
            猜你喜欢
            • 1970-01-01
            • 2018-07-27
            • 2020-02-11
            • 1970-01-01
            • 1970-01-01
            • 2017-03-19
            • 2021-07-16
            • 2018-07-08
            • 1970-01-01
            相关资源
            最近更新 更多