0

I am learning to use Firebase and want to know if I am doing it right. If I understood correctly, you can only retrieve data asynchronously using a listener in Firebase. I will try to explain my question with an example. Say I have the following database data for a simple chat application:

chat_info:
  chatID_1:
    participants:
      uId_1: true
      uId_2: true

users:
  uId_1:
    display_name: "David"
    participated_chats:
      chatID_1: true
      chatID_2: true
  uId_2:
    display_name: "Jason"
    participated_chats:
      chatID_1: true
      chatID_2: true

Now, I am trying to list the chats that David is participated in. So I do something like the following:

    ArrayList<String> chatIdList = new ArrayList<String>();
    // Retrieve chat Ids of participating chats
    usersRef.child(mFirebaseUser.getUid()).child("participated_chats").addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            chatIdList.clear();

            // Save each chat Id to an arraylist
            for (DataSnapshot child : dataSnapshot.getChildren()) {
                chatIdList.add(child.getKey());

                // when loop hits the last user of the dataSnapsot
                if(chatIdList.size() >= dataSnapshot.getChildrenCount()) {

                    // For each chat Id, retrieve participants' uIds
                    for(String chatId : chatIdList) {
                        chatInfoRef.child(chatId).addListenerForSingleValueEvent(new ValueEventListener() {
                            @Override
                            public void onDataChange(DataSnapshot dataSnapshot) {
                                Chat chat = dataSnapshot.getValue(Chat.class);  // In a Chat class, there is public Map<String, Boolean> participants = new HashMap<>();
                                chatDetailList.add(chat);
                                chatListAdapter.notifyDataSetChanged();
                            }
                            @Override
                            public void onCancelled(DatabaseError databaseError) {}
                        });

                    }
                }
            }
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });

Now, I have participants' uIds for each chat that a user is participated in. But, since I want to display the username, not the uId, I have to retrieve data from another node again. Here is my worry because I have to add another asynchronous listner to retrieve data from different node. If it was something like MySQL, it would not be a problem, but Firebase listener is asynchronous. This idea of asynchronous listener to retrieve data is very confusing and wonders if I am doing it right. What should I do here?

Megool
  • 963
  • 2
  • 8
  • 29
  • At first glance this looks fine: you're looping on the client to "join" the user data from the database. What's the problem? – Frank van Puffelen Oct 20 '16 at 14:09
  • When I loop on a user data using an asynchronous listener, is it guaranteed that the values are returned in order? In other words, when a first listener is run, the second listener runs right after, whether or not the first listener returned a value because its task is asynchronous. So I am wondering if multiple listeners are run asynchronously and, is it possible that the returned values are added to an arraylist unorderly? – Megool Oct 21 '16 at 06:41
  • 1
    All traffic to the database goes over the same socket, so they are all executed in order. See [this answer](http://stackoverflow.com/questions/35931526/speed-up-fetching-posts-for-my-social-network-app-by-using-query-instead-of-obse/35932786#35932786) to learn a bit more about that pipelining. – Frank van Puffelen Oct 21 '16 at 14:12
  • That answers my question! Thank you very much Frank :) – Megool Oct 21 '16 at 15:33

1 Answers1

1

You can just attach the first listener to the /users/uId_1 to get the whole user object, and then you can simply get the user's username / display name from the dataSnapshot value.

Here's an example.

ArrayList<String> chatIdList = new ArrayList<String>();
// Retrieve chat Ids of participating chats
usersRef.child(mFirebaseUser.getUid()).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        chatIdList.clear();

        User user = dataSnapshot.getValue(User.class);
        String username = user.getDisplay_name();

        Map<String, Boolean> participated_chats = user.getParticipated_chats();
        // Save each chat Id to an arraylist
        for (Map.Entry<String, Boolean> child : participated_chats.entries()) {
            chatIdList.add(child.getKey());

            // ... continues
        }
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {

    }
});
Wilik
  • 7,630
  • 3
  • 29
  • 35