Search code examples
androidfirebasefirebase-realtime-databasewait

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?


Solution

  • 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...
                });
            }
        }
    });