如何从 Android 上的 Firebase DataSnapshot 中提取对象列表

Posted

技术标签:

【中文标题】如何从 Android 上的 Firebase DataSnapshot 中提取对象列表【英文标题】:How to extract a list of objects from Firebase DataSnapshot on android 【发布时间】:2015-12-29 10:43:12 【问题描述】:

我想将所有 Firebase DataSnapshot 子级转换为 android 中的列表。

类似这样的:

mFirebaseRef = new Firebase(FIREBASE_URL);

mFirebaseRef.addValueEventListener(new ValueEventListener() 
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) 
        List<String> td = (ArrayList<String>) dataSnapshot.getValue();
        //notifyDataSetChanged();
    

    @Override
    public void onCancelled(FirebaseError firebaseError) 

    
);

【问题讨论】:

可能重复:***.com/questions/27848313/… 在下面回答。但这部分是一种猜测,因为“它不起作用”非常模糊,而且您没有包含数据的 sn-p。如果我的回答不能解决您的问题:您会遇到什么错误?你的数据是什么样的(复制/粘贴样本,没有截图也没有描述)? 试试这个:***.com/questions/32886546/… 【参考方案1】:

Firebase 以这种格式存储一系列值:

"-K-Y_Rhyxy9kfzIWw7Jq": "Value 1"
"-K-Y_RqDV_zbNLPJYnOA": "Value 2"
"-K-Y_SBoKvx6gAabUPDK": "Value 3"

如果这就是你拥有它们的方式,那么你得到了错误的类型。上述结构表示为Map,而不是List

mFirebaseRef = new Firebase(FIREBASE_URL);

mFirebaseRef.addValueEventListener(new ValueEventListener() 
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) 
        Map<String, Object> td = (HashMap<String,Object>) dataSnapshot.getValue();

        List<Object> values = td.values();

        //notifyDataSetChanged();
    

    @Override
    public void onCancelled(FirebaseError firebaseError) 

    
);

【讨论】:

我想要“-K-Y_Rhyxy9kfzIWw7Jq”的父列表:“值 1”“-K-Y_RqDV_zbNLPJYnOA”:“值 2”“-K-Y_SBoKvx6gAabUPDK”:“值 3” 可以Map&lt;String, MyDataObject&gt; = (HashMap&lt;String, MyDataObject&gt;) dataSnapshot.getValue(); 还是必须将Object 转换为MyDataObject? @Frank,Android Studio 在这一行显示红色下划线 List values =td.values();...错误:- 无法将集合对象转换为列表对象..在堆栈跟踪中抛出错误.. @Frank 谢谢,List&lt;Object&gt; values = td.values(); 很高兴知道。 @NarendraBaratam 我有同样的问题。改用这种方式:List&lt;Object&gt; values = new Arraylist&lt;&gt;(td.values());【参考方案2】:

我希望下面的代码有效

Firebase ref = new Firebase(FIREBASE_URL);

  ref.addValueEventListener(new ValueEventListener() 
      @Override
      public void onDataChange(DataSnapshot snapshot) 
          Log.e("Count " ,""+snapshot.getChildrenCount());
          for (DataSnapshot postSnapshot: snapshot.getChildren()) 
            <YourClass> post = postSnapshot.getValue(<YourClass>.class);
            Log.e("Get Data", post.<YourMethod>());
          
      
      @Override
      public void onCancelled(FirebaseError firebaseError) 
          Log.e("The read failed: " ,firebaseError.getMessage());
      
  );

【讨论】:

当我打印日志时它为空。你能帮帮我吗? 如果您只需要该数据一次,请不要忘记使用addListenerForSingleValueEvent() 而不是addValueEventListener()【参考方案3】:

将数据保存和检索到 - 从 Firebase (不推荐使用 2.4.2 版)

Firebase fb_parent = new Firebase("YOUR-FIREBASE-URL/");
Firebase fb_to_read = fb_parent.child("students/names");
Firebase fb_put_child = fb_to_read.push(); // REMEMBER THIS FOR PUSH METHOD

//INSERT DATA TO STUDENT - NAMES  I Use Push Method
fb_put_child.setValue("Zacharia"); //OR fb_put_child.setValue(YOUR MODEL) 
fb_put_child.setValue("Joseph"); //OR fb_put_child.setValue(YOUR MODEL) 
fb_put_child.setValue("bla blaaa"); //OR fb_put_child.setValue(YOUR MODEL) 

//GET DATA FROM FIREBASE INTO ARRAYLIST
fb_to_read.addValuesEventListener....
    public void onDataChange(DataSnapshot result)
        List<String> lst = new ArrayList<String>(); // Result will be holded Here
        for(DataSnapshot dsp : result.getChildren())
            lst.add(String.valueOf(dsp.getKey())); //add result into array list
        
        //NOW YOU HAVE ARRAYLIST WHICH HOLD RESULTS




for(String data:lst) 
         Toast.make(context,data,Toast.LONG_LENGTH).show; 
       
    

【讨论】:

【参考方案4】:

我做了这样的事情:

Firebase ref = new Firebase(FIREBASE_URL);
ref.addValueEventListener(new ValueEventListener() 

@Override
public void onDataChange(DataSnapshot snapshot) 
    Map<String, Object> objectMap = (HashMap<String, Object>)    
             dataSnapshot.getValue();
    List<Match> = new ArrayList<Match>();
    for (Object obj : objectMap.values()) 
        if (obj instanceof Map) 
            Map<String, Object> mapObj = (Map<String, Object>) obj;
            Match match = new Match();
            match.setSport((String) mapObj.get(Constants.SPORT));
            match.setPlayingWith((String) mapObj.get(Constants.PLAYER));
            list.add(match);
        
    
  
  @Override
  public void onCancelled(FirebaseError firebaseError) 

  
);

【讨论】:

我理解对了吗?即使您只添加一个匹配类型值,您每次都在循环?【参考方案5】:
FirebaseDatabase mFirebaseDatabase = FirebaseDatabase.getInstance();
 DatabaseReference databaseReference =    mFirebaseDatabase.getReference(FIREBASE_URL);
        databaseReference.addValueEventListener(new ValueEventListener() 
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) 

                for (DataSnapshot childDataSnapshot : dataSnapshot.getChildren()) 
                    Log.v(TAG,""+ childDataSnapshot.getKey()); //displays the key for the node
                    Log.v(TAG,""+ childDataSnapshot.child(--ENTER THE KEY NAME eg. firstname or email etc.--).getValue());   //gives the value for given keyname
                
            
        @Override
        public void onCancelled(DatabaseError databaseError) 

        
    );

希望对你有帮助!

【讨论】:

【参考方案6】:

在我的情况下,只有给定的解决方案可以正常工作。

Firebase ArrayList 结构的屏幕截图

如何从 DataSnapshotFirebase 获取整个列表

GenericTypeIndicator<Map<String, List<Education>>> genericTypeIndicator = new GenericTypeIndicator<Map<String, List<Education>>>() ;
Map<String, List<Education>> hashMap = dataSnapshot.getValue(genericTypeIndicator);

for (Map.Entry<String,List<Education>> entry : hashMap.entrySet()) 
      List<Education> educations = entry.getValue();
        for (Education education: educations)
             Log.i(TAG, education.Degree);
         

Education.java:(模型类)。

public class Education implements Serializable

    public String Degree;
    public String Result;

希望这会正常工作。

【讨论】:

【参考方案7】:

正如弗兰克所说,Firebase"key": "Value" 的格式存储值序列 这是一个地图结构

要从此序列中获取 List,您必须

    使用 StringHashMap 和您的 Object 初始化 GenericTypeIndicator。 将 DataSnapShot 的值作为 GenericTypeIndicator 获取到 Map。 用 HashMap 值初始化 ArrayList

GenericTypeIndicator<HashMap<String, Object>> objectsGTypeInd = new GenericTypeIndicator<HashMap<String, Object>>() ;
Map<String, Object> objectHashMap = dataSnapShot.getValue(objectsGTypeInd);
ArrayList<Object> objectArrayList = new ArrayList<Object>(objectHashMap.values());

对我来说很好,希望对你有帮助。

【讨论】:

发现这个埋在 doco firebase.com/docs/java-api/javadoc/com/firebase/client/…【参考方案8】:
mDatabase.child("token").addListenerForSingleValueEvent(new ValueEventListener() 
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) 
              for (DataSnapshot snapshot:dataSnapshot.getChildren())
              
                 String key= snapshot.getKey();
                 String value=snapshot.getValue().toString();
              
            

            @Override
            public void onCancelled(DatabaseError databaseError) 
                Toast.makeText(ListUser.this,databaseError.toString(),Toast.LENGTH_SHORT).show();
            
        );

只有在孩子没有SubChild时才有效

【讨论】:

【参考方案9】:

你需要编写一个自定义的 Deserializer,然后循环它并获取 hasmap 的值。

自定义反序列化器:-

public class UserDetailsDeserializer implements JsonDeserializer<AllUserDetailsKeyModel> 
  /*
    bebebejunskjd:
      "email": "akhilbv1@gmail.com",
          "mobileNum": "12345678",
          "password": "1234567",
          "username": "akhil"*/
  @Override public AllUserDetailsKeyModel deserialize(JsonElement json, Type typeOfT,
      JsonDeserializationContext context) throws JsonParseException 

    final JsonObject jsonObject = json.getAsJsonObject();

    Gson gson = new Gson();

    Type AllUserDetailsResponseModel =
        new TypeToken<HashMap<String, AllUserDetailsResponseModel>>().getType();

    HashMap<String, AllUserDetailsResponseModel> user =
        gson.fromJson(jsonObject, AllUserDetailsResponseModel);
    AllUserDetailsKeyModel result = new AllUserDetailsKeyModel();
    result.setResult(user);
    return result;
  



cmets 中的代码是我的对象模型,你应该用你的模型类替换AllUserDetailsKeyModel 并将其添加到其余客户端,如下所示:-

private Converter.Factory createGsonConverter() 
    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(AllUserDetailsKeyModel.class, new UserDetailsDeserializer());
    Gson gson = gsonBuilder.create();
    return GsonConverterFactory.create(gson);
  

这是用于改造的自定义转换器。

在您的 onResponse 中,您只需循环使用 hasmaps 并按键获取值,我的模型类如下所示:-

public class AllUserDetailsKeyModel 

  private Map<String, AllUserDetailsResponseModel> result;

  public Map<String, AllUserDetailsResponseModel> getResult() 
    return result;
  

  public void setResult(Map<String, AllUserDetailsResponseModel> result) 
    this.result = result;
  


您可能需要提供一个 T 类型,其中 T 是您的数据类型,而我的模型仅包含一个哈希图和 getter 和 setter。

最后将自定义转换器设置为改造如下:- .addConverterFactory(createGsonConverter())

如果您需要更多说明,请告诉我。

【讨论】:

【参考方案10】:

使用 GenericTypeIndicator 从 Firebase ArrayList 结构化数据库中获取子节点列表

   //Start of Code
   Firebase ref = new Firebase(FIREBASE_URL);
   ref.addValueEventListener(new ValueEventListener()
      @Override
      public void onDataChange(DataSnapshot snapshot)
         GenericTypeIndicator<List<YourClassName>> t = new GenericTypeIndicator<List<YourClassName>>;
         List<YourClassName> messages = snapshot.getValue(t);
         Log.d("Get Data Size", messages.size());
          
      
      @Override
      public void onCancelled(FirebaseError firebaseError)
          Log.e("The read failed: ",firebaseError.getMessage());
      
   );

【讨论】:

【参考方案11】:

像魅力一样工作

final DatabaseReference senderDb = FirebaseDatabase.getInstance().getReference(Constant.NODE_MESSAGE).child(myId + "_" + otherId);

    senderDb.addValueEventListener(new ValueEventListener() 
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) 
            Map<String, Object> td = (HashMap<String,Object>) dataSnapshot.getValue();

            for (DataSnapshot childDataSnapshot : dataSnapshot.getChildren()) 
                DatabaseReference objRef = senderDb.child( childDataSnapshot.getKey());
                Map<String,Object> taskMap = new HashMap<String,Object>();
                taskMap.put("is_read", "1");
                objRef.updateChildren(taskMap); //should I use setValue()...?
                Log.v("Testing",""+ childDataSnapshot.getKey()); //displays the key for the node
            

            //notifyDataSetChanged();
        

        @Override
        public void onCancelled(DatabaseError databaseError) 

        

    );

【讨论】:

【参考方案12】:

你的问题是为什么你的代码不起作用。

这是你的代码:

Firebase ref = new Firebase(FIREBASE_URL);

  ref.addValueEventListener(new ValueEventListener() 
      @Override
      public void onDataChange(DataSnapshot snapshot) 
          Log.e("Count " ,""+snapshot.getChildrenCount());
          for (DataSnapshot postSnapshot: snapshot.getChildren()) 
            <YourClass> post = postSnapshot.getValue(<YourClass>.class);
            Log.e("Get Data", post.<YourMethod>());
          
      
      @Override
      public void onCancelled(FirebaseError firebaseError) 
          Log.e("The read failed: " ,firebaseError.getMessage());
      
  )

你错过了最简单的事情:getChildren()

FirebaseDatabase db = FirebaseDatabase.getInstance();
DatabaseReference reference = FirebaseAuth.getInstance().getReference("Donald Trump");

reference.addValueEventListener(new ValueEventListener() 
   @Override
   public void onDataChange(DataSnapshot dataSnapshot) 

            int count = (int) dataSnapshot.getChildrenCount(); // retrieve number of childrens under Donald Trump

            String[] hairColors = new String[count];

            index = 0;
            for (DataSnapshot datas : dataSnapshot.getChildren())

                hairColors[index] = datas.getValue(String.class);

            
            index ++

            for (int i = 0; i < count; i++)
            Toast(MainActivity.this, "hairColors : " + hairColors[i], toast.LENGTH_SHORT).show();

            

    

        @Override
        public void onCancelled(DatabaseError databaseError) 

        

    );

【讨论】:

索引++;必须在 for (DataSnapshot datas : dataSnapshot.getChildren())【参考方案13】:
ArrayList<String> keyList = new ArrayList<String>();
mKeyRef.addValueEventListener(new ValueEventListener() 
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) 
            for (DataSnapshot childDataSnapshot : dataSnapshot.getChildren()) 
                String temp = childDataSnapshot.getKey();
                keyList.add(temp);
                i = keyList.size();

            
        
        @Override
        public void onCancelled(DatabaseError databaseError) 
            throw databaseError.toException();
        
    );

这段代码可以很好地将所有firebase键添加到arraylist中,您可以使用firebase值或其他静态值来完成。

【讨论】:

不鼓励仅使用代码的答案。请edit您的答案并添加一些文字来解释它如何解决问题和/或它与其他答案的不同之处。【参考方案14】:
    @Override
       public void onDataChange(DataSnapshot dataSnapshot) 
           for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) 
               User user = postSnapshot.getValue(User.class);
               list.add(user);
           
           for (int i=0;i<list.size();i++)
           
               Log.e("Name",list.get(i).getname());
               Log.e("Phone",list.get(i).getphone());

           
       
       @Override
       public void onCancelled(FirebaseError firebaseError) 
       Log.e("error",firebaseError.getMessage());
       
   );

类模型

class User

String name;

String phone;

public String getname() 
    return name;


public void setname(String name) 
    this.name = name;



public String getphone() 
    return phone;


public void setphone(String phone) 
    this.phone = phone;


列表绑定

List<User> list= new ArrayList <>();

这项工作适合你

【讨论】:

【参考方案15】:
DatabaseReference mRootRef = FirebaseDatabase.getInstance().getReference();
        DatabaseReference mMainMenuRef = mRootRef.child("tut_master");//main
        DatabaseReference mSubMenuRef = mMainMenuRef.child("english");//sub
        List<Tutorial>   tutorialNames=new ArrayList<>();
        mSubMenuRef.addValueEventListener(new ValueEventListener() 
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) 

                for(DataSnapshot ds : dataSnapshot.getChildren()) 
                    long id = ds.child("id").getValue(Long.class);
                    String name = ds.child("name").getValue(String.class);

                    Tutorial tut = new Tutorial();
                    tut.setTutId(id+"");
                    tut.setTutName(name);
                    tutList.add(tut);

                

            

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) 

            


        );

【讨论】:

【参考方案16】:
 private FirebaseDatabase firebaseDatabase=  FirebaseDatabase.getInstance();
    private DatabaseReference databaseReference=  firebaseDatabase.getReference();
    private DatabaseReference mChildReference= databaseReference.child("data");

  mChildReference.addValueEventListener(new ValueEventListener() 
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) 
                for(DataSnapshot ds : dataSnapshot.getChildren()) 
                    User commandObject = ds.getValue(User.class);
                    Log.d("TAG", commandObject.getMsg());
                
                Toast.makeText(MainActivity.this,dataSnapshot.toString(),Toast.LENGTH_SHORT).show();
            

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) 

            
        );

这会对你有所帮助,你只需要创建一个包含 String msg 的模型类。

【讨论】:

【参考方案17】:

使用 Gson 是我最喜欢的解决方案。

mFirebaseRef.addValueEventListener(new ValueEventListener() 
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) 
        Type StringListType = new TypeToken<List<String>>().getType();
        List<String> td = new Gson().fromJson(dataSnapshot.getValue(), StringListType);
    
);

如果您认为获取 TypeToken 的代码不直观。您可以编写一个类来包含您需要的所有类型。所以下次,你可以快速获得这些类型。

class TypeTokens
    static public final Type StringListType = new TypeToken<List<String>>().getType();
    static public final Type StringMapType = new TypeToken<Map<String, String>>().getType();
    static public final Type LongMapType = new TypeToken<Map<String, Long>>().getType();
    static public final Type DateMapType = new TypeToken<Map<String, Date>>().getType();

【讨论】:

【参考方案18】:

如果你使用 Kotlin,下一个是一个很好的解决方案:

myRef.addListenerForSingleValueEvent(object : ValueEventListener 
  override fun onDataChange(dataSnapshot: DataSnapshot) 
      val list = dataSnapshot.children.map  it.getValue(YourClass::class.java)!! 
      Log.d("TAG", "Value is: $list")

【讨论】:

以上是关于如何从 Android 上的 Firebase DataSnapshot 中提取对象列表的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Android 上的 Firebase 存储正确下载多个文件?

如何从 Android 上的 Firebase DataSnapshot 中提取对象列表

如何从 Android 上的 Firebase DataSnapshot 中提取对象列表

如何在 Android 上的 Firebase 存储中设置持久性?

我如何在Android应用上运行自动机器人测试?就像Firebase测试实验室上的那个]] << [

动态创建的 Firebase 动态链接不适用于 Android