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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/47705534/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 02:40:29  来源:igfitidea点击:

DatabaseException: Can't convert object of type java.lang.String to type

javaandroidfirebasefirebase-realtime-database

提问by Desmond Chin

I've looked at a few other answers for similar problems but don't understand why mine isn't working.

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

I'm trying to get my app to read commands from Firebase and move a drone. The command in firebase comes from a separate software. The app is built on top of the Parrot Drone SDK Sample code.

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

It seems to be able to get the text from the command object and append it to a textview, but when a new child is added it just crashes. I'm getting this error when a new child is added.

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

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

A sample of my data structure in firebase is below.

我在 firebase 中的数据结构示例如下。

{
"drones" : {
    "commands" : {
    "-L-n9HwaQktOdI2VEVlH" : {
        "executed" : false,
        "text" : "TAKE_OFF",
        "timestamp" : 1.512686825309134E9
    },
    "-L-nAuK5Ifde7Cdnan8K" : {
        "executed" : false,
        "text" : "LAND",
        "timestamp" : 1.512687248764272E9
    }
    }
}
}

The function in my activity to get data from firebase looks like this.

我的活动中从 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);
    }

My CommandObject class looks like this.

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

I've also tried using a value event listener instead, but the same problem occured.

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

采纳答案by Alex Mamo

You are getting this error:

您收到此错误:

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

Because you are trying to read the data of type Stringwhich is of type CommandObjectand that why you are getting this error.

因为您正在尝试读取类型String为类型的数据,这CommandObject就是您收到此错误的原因。

A more simple way to get those values would be to use the Stringclass like this:

获取这些值的更简单方法是使用这样的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);

And this the approach using an object of CommandObjectclass:

这是使用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);

In both cases your output will be:

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

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

回答by Desmond Chin

The solution provided by Alex worked but didn't quite answer why I couldn't get store my data in an object, and for my app while the child added listener, the app is able to read data that was already on Firebase but when new child is added, the value is empty.

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

    onChildAdded:DataSnapshot { key = -L0JjGo-3QMYDsuTMQcN, value =  }

I've done a little more digging to find out what might be causing this and found that it is probably caused because the values were not all written at the same time. And looking at firebase it seems that the key is added first, then the values are added. This is why the error says can't convert, it is because it doesn't exist. I'm using the Python Firebase Admin SDK to add the data to Firebase, so I'm not sure if this is the reason for that.

我做了更多的挖掘以找出可能导致这种情况的原因,并发现这可能是因为这些值不是同时写入的。并且查看 firebase 似乎是先添加键,然后添加值。这就是错误说无法转换的原因,因为它不存在。我正在使用 Python Firebase Admin SDK 将数据添加到 Firebase,所以我不确定这是否是原因。

So to fix my problem I moved my code to the onChildChanged function and added a check so that the code only runs when all of the data I need exists. This way I can get the values stored in an object straight away.

因此,为了解决我的问题,我将代码移至 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();
            }
        }
    }

回答by Pedro Gonzalez

Alex posted the right solution for me, but since I was using firebase-ui and kotlin, the code used is different. More info here

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

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

回答by N.Hubert

I faced a similar issue where I could not retrieve the data from the database; having a DatabaseExceptionerror with a message

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

can't convert from this type to that type.

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

The mistake I was making was I was writing incorrectly to the database. I wrote something like ...

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

mdatabaseReference.setValue(myObject)

instead of

代替

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

So essentially the answer I am suggesting is: you should ensure your data is written correctly to the database at the right node in the JSON tree if not you would likely get this kind of error when you are reading from the database.

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

回答by Asayaporn Pichet

you can use constructor oop normally like this

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

it's the same and no Error anymore

它是一样的,不再有错误

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

fill it and make sure your reference in firebase data should not be empty

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

回答by Waran-

In my case the problem was, that I using Kotlin class, and there were no default constructor such as

就我而言,问题是,我使用 Kotlin 类,并且没有默认构造函数,例如

 constructor() : this(0, "")

回答by Caner Y?lmaz

if u are using map object in your database should use get method directly with your object

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

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

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