0

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.

5
  • Isn't firebase Json based? Commented Jun 1, 2017 at 18:03
  • @LunarWatcher: yes, it is Commented Jun 1, 2017 at 18:03
  • Do you parse it correctly? Commented Jun 1, 2017 at 18:24
  • @LunarWatcher: Yes parsing is correct. But the arrayList is getting filled after sometimes ,, like I am missing some listener Commented Jun 1, 2017 at 18:34
  • Are you expecting arrID to be populated by the time that log statement is executed immediately after adding listeners? Commented Jun 1, 2017 at 19:12

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.