【问题标题】:Android Firebase retrieve data from child nodeAndroid Firebase 从子节点检索数据
【发布时间】:2016-07-24 10:25:07
【问题描述】:

我正在尝试从 Firebase 子节点获取数据。但它会抛出Can't convert object of type java.lang.String to type uk.co.stableweb.geethika.model.DailyVerse 异常。

这是我的 Firebase 数据库的结构。

这里是代码。我正在使用 Android Firebase 新 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);

还有模型类。

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

还有 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)

但是如果我如下更改数据库引用。并获取dataSnapshot值,抓取数据。

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

我认为可以使用 HashMap 获取这些值。但有评论说不再推荐。

【问题讨论】:

  • 此处的类型不匹配,请检查您在 firebase 数据库中为 verse_content 声明的类型
  • 我不明白,Android数据库不是将值存储为json,所以type是string对吗?

标签: android firebase firebase-realtime-database


【解决方案1】:

请特别注意 JSON 中的属性名称和 Java 代码中的字段/getter。如果它们不匹配,Firebase 客户端将无法匹配它们之间的值。

您的 JSON 有 verse_titleverse_content,因此您的 Java 类必须是其中一个

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

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

从 Firebase Android SDK 9.2 开始,您还可以注释 Java 代码以映射到正确的 JSON 属性。所以获得正确映射的第三种方法是:

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

我还没有尝试过最新的变体,所以如果答案中有错别字,请告诉我。

【讨论】:

    【解决方案2】:

    通过这种方法

    mRef.addChildEventListener(childEventListener);
    

    你订阅

    .child("daily_verse");
    

    儿童。 daily_verse 有两个孩子:verse_content 和 verse_title。这些孩子的类型是字符串。因此,您在 onChildAdd 监听器中获得了两个字符串数据快照。

    更新: 试试这样的:

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

    您应该从父对象订阅事件并检查事件监听器的键。

    【讨论】:

    • 是的,但是它返回字符串。如果返回的值是对象,为什么我不能使用下面的语句。 dailyVerse = dataSnapshot.getValue(DailyVerse.class);
    • 还是不行。我得到日志为 D/TEST: DataSnapshot { key = daily_verse, value = {verse_title=ගීතාවලිය 119:30, verse_content=විශ්වාසකමේ මාර්ගය ග෭රා ඔබගේ විනිශ්චයන් මා ඉදිරියෙහි තබා ගතිමි.} } D/儿童事件,添加诗句:geethika
    • 会抛出异常吗?
    • 没有。但模型为空。如果我尝试获取模型值,它会显示异常 NullPointerException。这意味着 dataSnapshot 没有将任何值传递给模型类。
    • @Isuru 我再次更新了代码。请把输出发给我。另外,如果您向我发送指向您的代码的链接会很好。我会检查的。
    【解决方案3】:
    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) {
    
                }
    });
    

    【讨论】:

      【解决方案4】:

      使用 firebase 模型类时,您必须包含一个空的构造函数以供 firebase 使用。

      尝试将其添加为

      public class DailyVerse {
          public DailyVerse(){
      
          }
      }
      

      【讨论】:

        【解决方案5】:
        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);
                    }
                }
        

        如果您无法获取数据,那么您可以获取该格式的数据。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多