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.
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$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)
A sample of my data structure in firebase is below.
{
"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.
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.
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.
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 String
which is of type CommandObject
and that why you are getting this error.
A more simple way to get those values would be to use the String
class like this:
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 CommandObject
class:
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