Animesh Jena
Animesh Jena

Reputation: 1551

ArrayList is showing empty after getting data from firebase database

I am implementing firebase in my app. Please refer the below image as a reference to my database.

The SLC Structure

I have an array of SLC names and I need to generate an arrayList of SLC keys. So I am trying to create an arrayList of specific SLC keys. Please see the below code once.

for (int i = 0; i < arr.size(); i++)
{
    Query query = ref.child(pref.getString("groupSelectedDCU", "") + "/" + "DeviceList")
                     .orderByChild("name")
                     .equalTo(arr.get(i));
    query.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            for (DataSnapshot child: dataSnapshot.getChildren())
            {
                Log.d("arrID", child.getKey() + "");
                arrID.add(child.getKey());
            }

            Log.d("arrID", Arrays.toString(arrID.toArray()));
        }

        @Override
        public void onCancelled(FirebaseError firebaseError) {
        }
    });
}
Log.d("arrID", Arrays.toString(arrID.toArray()));

Here I am trying to add all the SLC keys into the arrID arraylist. But while accessing the arrayList, it returns an empty array. Am I missing something or do I have to add any more listeners? Need your help.

Upvotes: 0

Views: 1566

Answers (1)

Paulo Mattos
Paulo Mattos

Reputation: 19339

You misunderstood how addListenerForSingleValueEvent works. The provided ValueEventListener methods will be called asynchronously in the background, when the query response finally arrives from the network. As such, when this last statement runs (after the for loop):

...
Log.d("arrID", Arrays.toString(arrID.toArray()));

the arrID will still be empty since none of the onDataChange methods has been called yet.

Alternative solution. If you need to wait until all queries are done, try this instead:

List<String> arrID = ArrayList<String>();
int remainingQueries = arr.size(); 
for (int i = 0; i < arr.size(); i++) {
    Query query = ...
    query.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            for (DataSnapshot child: dataSnapshot.getChildren()) {
                Log.d("arrID", child.getKey() + "");
                arrID.add(child.getKey());
            }
            Log.d("arrID", Arrays.toString(arrID.toArray()));
            if (--remainingQueries == 0) onQueriesDone(arrID);
        }
        @Override
        public void onCancelled(FirebaseError firebaseError) { }
    });
}

which will call this method when done:

private void onQueriesDone(List<String> arrID) {
    Log.d("arrID", Arrays.toString(arrID.toArray()));
}

In particular, we don't need synchronization locks to access the shared counter remainingQueries since all Firebase callbacks are triggered on the main thread.

Upvotes: 2

Related Questions