faraz_ahmed_kamran faraz_ahmed_kamran - 2 months ago 15
Android Question

Android Firebase wait for data

in my android application I create an activity which contains a

ListView
which is populated with data from Firebase Database.

The JSON Tree of the structure of the database is the following:

{
"companies" : {
"companyX" : {
"address" : "50th avenue, NY",
"name" : "Spare-Tools Ltd."
},
"companyZ" : {
"address" : "50th Broadway, NY",
"name" : "Burgers and Burgers"
}
},
"company-requests" : {
"companyX" : {
"req1" : true
"req2" : true
}
},
"requests" : {
"req1" : {
"destination" : "Upper Tooting 122, Bronx",
"origin" : "Philadelphia",
"time" : "1473593287",
...
}
"req2" : {
...
}
}
}


I want to populate the
ListView
with the list of requests from the
requests
node. But I first need to know all requests that belong to a specific company so I first go to the
company-requests
node and retrieve all the request-keys belonging to the specific company.
The problem I am facing is that the
ListView
is created before the final data from the database arrived:

public class RequestsListActivity extends AppCompatActivity {
private ListView rListView;
DatabaseReference rootNode = FirebaseDatabase.getInstance().getReference();

@Override
protected void onCreate(Bundle savedInstanceState) {
...
rListView = (ListView) findViewById(R.id.result_list_view);
//First I retrieve all the requests of a specific company
DatabaseReference companyRequests = rootNode.child("company-requests/companyX");

companyRequests.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
//Then I retrieve all the keys of these requests
...
while (iterator.hasNext()) {
String key = iterator.next().getKey();
//For each key I retrieve its details from the requests node
DatabaseReference currRequest = rootNode.child("requests/" + key);
currRequest.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
String time;
time = (String) dataSnapshot.child("time").getValue();
Request request = new Request(time);
allRequests.add(request);
}
...onCancelled...
});
}
//THIS CODE IS EXECUTED TO EARLY: BEFORE WE HAVE ANY DATA FROM FIREBASE
RequestAdapter adapter = new RequestAdapter(RequestsListActivity.this, allRequests);
rListView.setAdapter(adapter);

}

...onCancelled...
});
}
}


How can I insert a
wait
(spinner?) that waits until the values are loaded from Firebase?

Answer

You can use a simple counter to keep track of the number of pending loads:

companyRequests.addValueEventListener(new ValueEventListener() {
    public void onDataChange(DataSnapshot dataSnapshot) {
        // at the start we need to still load all children
        final long[] pendingLoadCount = { dataSnapshot.getChildrenCount() };
        for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
            //For each key I retrieve its details from the requests node
            DatabaseReference currRequest = rootNode.child("requests/" + childSnapshot.getKey());
            currRequest.addListenerForSingleValueEvent(new ValueEventListener() {
                public void onDataChange(DataSnapshot dataSnapshot) {
                    String time;
                    time = (String) dataSnapshot.child("time").getValue();
                    Request request = new Request(time);
                    allRequests.add(request);

                    // we loaded a child, check if we're done
                    pendingLoadCount[0] = pendingLoadCount[0] - 1;
                    if (pendingLoadCount[0] == 0) {
                        RequestAdapter adapter = new RequestAdapter(RequestsListActivity.this, allRequests);
                        rListView.setAdapter(adapter);
                    }
                }
                ...onCancelled...
            });
        }
    }
});