简体   繁体   中英

Android Firebase retrieve data from child node

I'm trying to get the data from Firebase child node. But it throws Can't convert object of type java.lang.String to type uk.co.stableweb.geethika.model.DailyVerse exception.

This is the structure of my Firebase database.

Firebase数据库结构。

Here is the code. I'm using Android Firebase new documentation .

mRef = FirebaseDatabase.getInstance().getReference().child("daily_verse");
mRef.keepSynced(true);

ChildEventListener childEventListener = new ChildEventListener() {
    @Override
    public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
        Log.d("Child Event,Verse", dataSnapshot.getKey());

        dailyVerse = dataSnapshot.getValue(DailyVerse.class);

    }

    @Override
    public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
        Log.d("Child Event,Verse", "onChildChanged:" + dataSnapshot.getKey());

        dailyVerse = dataSnapshot.getValue(DailyVerse.class);
    }

    @Override
    public void onChildRemoved(DataSnapshot dataSnapshot) {

    }

    @Override
    public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {

    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        Log.w("Firebase", "onCancelled", databaseError.toException());
        Toast.makeText(context, "Failed to load verse",
                Toast.LENGTH_SHORT).show();
    }
};

mRef.addChildEventListener(childEventListener);

And Model class.

public class DailyVerse {

    private String verse_title;
    private String verse_content;

    public String getVerseTitle() {
        return verse_title;
    }

    public void setVerseTitle(String verse_title) {
        this.verse_title = verse_title;
    }

    public String getVerseContent() {
        return verse_content;
    }

    public void setVerseContent(String verse_content) {
        this.verse_content = verse_content;
    }
}

And the LogCat.

com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type uk.co.stableweb.geethika.model.DailyVerse
  at com.google.android.gms.internal.zzalq.zzd(Unknown Source)
  at com.google.android.gms.internal.zzalq.zzb(Unknown Source)
  at com.google.android.gms.internal.zzalq.zza(Unknown Source)
  at com.google.firebase.database.DataSnapshot.getValue(Unknown Source)
  at uk.co.stableweb.geethika.VerseActivityFragment$1.onChildAdded(VerseActivityFragment.java:63)
  at com.google.android.gms.internal.zzahh.zza(Unknown Source)
  at com.google.android.gms.internal.zzajh.zzctc(Unknown Source)
  at com.google.android.gms.internal.zzajk$1.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:5461)
  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)

But if I change the database reference as follows. And get the dataSnapshot value, it grabs the data.

mRef = FirebaseDatabase.getInstance().getReference("daily_verse");

testVal = (String) dataSnapshot.getValue();
Log.d("TEST", testVal);

V/FA: Activity resumed, time: 278033062
D/Child Event,Verse added: verse_content
D/TEST: විශ්වාසකමේ මාර්ගය තෝරා ගතිමි. ඔබගේ විනිශ්චයන් මා ඉදිරියෙහි තබා ගතිමි.
D/Child Event,Verse added: verse_title
D/TEST: ගීතාවලිය 119:30

I think it is possible to get those values using HashMap. But there was a comment saying it is no longer recommended.

Pay careful attention to the names of your properties in the JSON and your fields/getters in the Java code. If they don't match, the Firebase client won't be able to match the values between them.

Your JSON has verse_title and verse_content , so your Java class must be either :

public class DailyVerse {
    public String verse_title;
    public String verse_content;    
}

or :

public class DailyVerse {

    private String verse_title;
    private String verse_content;

    public String getVerse_title() {
        return verse_title;
    }

    public void setVerse_title(String verse_title) {
        this.verse_title = verse_title;
    }

    public String getVerse_content() {
        return verse_content;
    }

    public void setVerse_content(String verse_content) {
        this.verse_content = verse_content;
    }
}

Since Firebase Android SDK 9.2, you can also annotate your Java code to map to the correct JSON properties. So a third way to get the correct mapping is:

public class DailyVerse {

    private String verse_title;
    private String verse_content;

    @PropertyName("verse_title")
    public String getVerseTitle() {
        return verse_title;
    }

    public void setVerseTitle(String verse_title) {
        this.verse_title = verse_title;
    }

    @PropertyName("verse_content")
    public String getVerseContent() {
        return verse_content;
    }

    public void setVerseContent(String verse_content) {
        this.verse_content = verse_content;
    }
}

I haven't tried that latest variant though, so let me know if there are typos on the answer.

By this method

mRef.addChildEventListener(childEventListener);

you subscribe for

.child("daily_verse");

children. daily_verse has two children: verse_content and verse_title. The type of these children is String. So, you get two String datasnapshot in the onChildAdd listener.

Update: Try something like this:

mRef = FirebaseDatabase.getInstance().getReference();
mRef.keepSynced(true);

ChildEventListener childEventListener = new ChildEventListener() {
    @Override
    public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
        Log.d("Child Event,Verse", dataSnapshot.getKey());
        if ("daily_verse".equal(dataSnapshot().getKey){
            dailyVerse = dataSnapshot.getValue(DailyVerse.class);
            Log.d("TEST","Object: "+dailyVerse);
            if (dailyVerse!=null){
               Log.d("TEST","values: "+dailyVerse.verse_title+", "+dailyVerse.verse_content);
            }
        }

    }

    @Override
    public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
        Log.d("Child Event,Verse", "onChildChanged:" + dataSnapshot.getKey());
        if ("daily_verse".equal(dataSnapshot().getKey){
          dailyVerse = dataSnapshot.getValue(DailyVerse.class);
          Log.d("TEST","Changed object: "+dailyVerse);
          if (dailyVerse!=null){
             Log.d("TEST","Changed values: "+dailyVerse.verse_title+", "+dailyVerse.verse_content);
          }
        }
    }

    @Override
    public void onChildRemoved(DataSnapshot dataSnapshot) {

    }

    @Override
    public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {

    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        Log.w("Firebase", "onCancelled", databaseError.toException());
        Toast.makeText(context, "Failed to load verse",
                Toast.LENGTH_SHORT).show();
    }
};

mRef.addChildEventListener(childEventListener);

You should subscribe to events from parent object and check the key at events listener.

DataRef = FirebaseDatabase.getInstance().getReference().child("Users");

DataRef.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                String acctname = (String)dataSnapshot.child("Name").getValue();
                String acctmail = (String)dataSnapshot.child("Email").getValue();

            }

            @Override
            public void onCancelled(DatabaseError databaseError) {

            }
});

When using a firebase model class, You have to include an empty constructor for firebase to work with.

Try adding it as

public class DailyVerse {
    public DailyVerse(){

    }
}
ArrayList<EventsResponse> usersEventsList = new ArrayList<>();
    dummyIdsArrayList = new ArrayList<>();
    Iterator<DataSnapshot> eventsIterator = dataSnapshot.getChildren().iterator();
    while (eventsIterator.hasNext()) {
        DataSnapshot eventsSnapShot = eventsIterator.next();
        EventsResponse eventsResponse = new EventsResponse();
        eventsResponse.setEventName(eventsSnapShot.getKey());
        Iterator<DataSnapshot> eventChildIterator = eventsSnapShot.getChildren().iterator();
        while (eventChildIterator.hasNext()) {
            DataSnapshot eventchildSnapshot = eventChildIterator.next();
            if (eventchildSnapshot.getKey().equals("is_recursive")) {
                eventsResponse.setRecursive((Boolean) eventchildSnapshot.getValue());
            } else if (eventchildSnapshot.getKey().equals("is_notif")) {
                eventsResponse.setNotif((Boolean) eventchildSnapshot.getValue());
            } else if (eventchildSnapshot.getKey().equals("is_editable")) {
                eventsResponse.setEditable((Boolean) eventchildSnapshot.getValue());
            } else if (eventchildSnapshot.getKey().equals("is_visible")) {
                eventsResponse.setVisible((Boolean) eventchildSnapshot.getValue());
            } else if (eventchildSnapshot.getKey().equals("name")) {
                eventsResponse.setName(eventchildSnapshot.getValue().toString());
            } else if (eventchildSnapshot.getKey().equals("date")) {
                Iterator<DataSnapshot> eventChildDateIterator = eventchildSnapshot.getChildren().iterator();
                while (eventChildDateIterator.hasNext()) {
                    DataSnapshot eventchildDateSnapshot = eventChildDateIterator.next();
                    if (eventchildDateSnapshot.getKey().equals("day")) {
                        eventsResponse.setDay(eventchildDateSnapshot.getValue().toString());
                    } else if (eventchildDateSnapshot.getKey().equals("month")) {
                        eventsResponse.setMonth(eventchildDateSnapshot.getValue().toString());
                    } else if (eventchildDateSnapshot.getKey().equals("year")) {
                        eventsResponse.setYear(eventchildDateSnapshot.getValue().toString());
                    }
                }
            } else {
                eventsResponse.setNotif(true);
                eventsResponse.setVisible(false);
            }
        }

if you are not able to fetch data,then you can fetch the data in that format.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM