webentwicklung-frage-antwort-db.com.de

DatabaseException: Objekt des Typs Java.lang.String kann nicht in Typ konvertiert werden

Ich habe mir ein paar andere Antworten für ähnliche Probleme angesehen, aber ich kann nicht verstehen, warum meine nicht funktioniert.

Ich versuche, dass meine App Befehle von Firebase liest und eine Drohne verschiebt. Der Befehl in der Firebase stammt von einer separaten Software. Die App basiert auf dem Parrot Drone SDK-Beispielcode.

Es scheint in der Lage zu sein, den Text vom Befehlsobjekt abzurufen und an eine Textansicht anzuhängen, aber wenn ein neues untergeordnetes Element hinzugefügt wird, stürzt es einfach ab. Ich erhalte diese Fehlermeldung, wenn ein neues Kind hinzugefügt wird.

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)

Ein Beispiel meiner Datenstruktur in Firebase ist unten aufgeführt.

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

Die Funktion in meiner Aktivität, Daten von Firebase abzurufen, sieht folgendermaßen aus.

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

Meine CommandObject-Klasse sieht so aus.

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

Ich habe auch versucht, stattdessen einen Wertereignislistener zu verwenden, aber dasselbe Problem trat auf.

4
Desmond Chin

Sie erhalten diese Fehlermeldung:

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

Weil Sie versuchen, die Daten des Typs String zu lesen, die vom Typ CommandObject sind und deshalb diese Fehlermeldung angezeigt wird.

Eine einfachere Methode zum Abrufen dieser Werte wäre die Verwendung der String-Klasse wie folgt:

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

Und dies der Ansatz mit einem Objekt der Klasse 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 beiden Fällen lautet Ihre Ausgabe:

false / TAKE_OFF / 1.512686825309134E9
false / LAND / 1.512687248764272E9
5
Alex Mamo

Die von Alex zur Verfügung gestellte Lösung hat funktioniert, aber nicht ganz beantwortet, warum ich meine Daten nicht in einem Objekt speichern konnte. Für meine App, während das untergeordnete Listener-Element hinzugefügt wurde, kann die App Daten lesen, die bereits auf Firebase vorhanden waren, jedoch neu waren Kind wird hinzugefügt, der Wert ist leer.

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

Ich habe ein wenig mehr nachgeforscht, um herauszufinden, was dies möglicherweise verursacht hat, und habe herausgefunden, dass dies wahrscheinlich daran liegt, dass die Werte nicht alle gleichzeitig geschrieben wurden. Wenn Sie sich Firebase anschauen, scheint es, als würde der Schlüssel zuerst hinzugefügt, dann werden die Werte hinzugefügt. Aus diesem Grund sagt der Fehler nicht konvertieren kann, weil er nicht existiert. Ich benutze das Admin-SDK von Python Firebase, um die Daten zu Firebase hinzuzufügen. Ich bin mir also nicht sicher, ob dies der Grund ist dafür.

Um mein Problem zu beheben, habe ich meinen Code in die onChildChanged-Funktion verschoben und eine Prüfung hinzugefügt, sodass der Code nur ausgeführt wird, wenn alle benötigten Daten vorhanden sind. Auf diese Weise kann ich die Werte sofort in einem Objekt speichern.

    @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();
            }
        }
    }
3
Desmond Chin

Alex hat die richtige Lösung für mich gepostet, aber da ich Firebase-Ui und Kotlin verwendet habe, ist der Code anders. Mehr Infos hier

    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)
        }
    }
1
Pedro Gonzalez

Ich hatte ein ähnliches Problem, bei dem ich die Daten nicht aus der Datenbank abrufen konnte. mit einem DatabaseException Fehler mit einer Nachricht

kann nicht von diesem Typ in diesen Typ konvertieren.

Der Fehler ich habe falsch in die Datenbank geschrieben. Ich schrieb so etwas wie ...

mdatabaseReference.setValue(myObject)

anstatt von

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

Die Antwort, die ich vorschlage, lautet also im Wesentlichen: Sie sollten sicherstellen, dass Ihre Daten korrekt in die Datenbank am richtigen Knoten in der JSON-Struktur geschrieben werden, wenn Sie diese Art von Fehler nicht wahrscheinlich beim Lesen aus der Datenbank erhalten.

0
N.Hubert

In meinem Fall bestand das Problem darin, dass ich die Kotlin-Klasse verwendete und es keinen Standardkonstruktor wie

 constructor() : this(0, "")
0
Waran-

sie können Konstruktor oop normalerweise so verwenden

es ist das gleiche und kein fehler mehr

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

füllen Sie es aus und stellen Sie sicher, dass Ihre Referenz in den Firebase-Daten nicht leer ist

0