2 votes

Android Firebase attend les données

Dans mon application Android, je crée une activité qui contient une ListView qui est alimenté par les données de la base de données Firebase.

L'arbre JSON de la structure de la base de données est le suivant :

{
  "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" : {
      ...
    }
  }
}

Je veux remplir le ListView avec la liste des demandes de l requests nœud. Mais j'ai d'abord besoin de connaître toutes les demandes qui appartiennent à une entreprise spécifique, donc je vais d'abord dans le noeud company-requests et récupère toutes les clés de demande appartenant à l'entreprise spécifique. Le problème auquel je suis confronté est que le ListView est créé avant que les données finales de la base de données n'arrivent :

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

Comment puis-je insérer un wait (spinner ?) qui attend que les valeurs soient chargées depuis Firebase ?

5voto

Frank van Puffelen Points 16029

Vous pouvez utiliser un simple compteur pour suivre le nombre de chargements en attente :

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

0voto

kerner1000 Points 1182

J'ai résolu ce problème en utilisant un java.util.concurrent.CountDownLatch :

Dans cet exemple, remplacez EquityTotalListener avec votre mise en œuvre de ValueEventListener .

private void recalculate() {
        final AtomicLong sumUpAll = new AtomicLong();
        final CountDownLatch cnt = new CountDownLatch(mapUid2GeoLocation.keySet().size());
        for (final String uid : mapUid2GeoLocation.keySet()) {
            EquityTotalListener el = mapUid2EquityListener.get(uid);
            if (el != null) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Listener for " + uid + " already set up");
                    cnt.countDown();
                }
            } else {
                el = new EquityTotalListener(database.getDatabase(), uid) {

                    @Override
                    public void onCancelled(final DatabaseError databaseError) {
                        super.onCancelled(databaseError);
                        cnt.countDown();
                    }

                    @Override
                    protected void valueChanged(final String key, final Object value) {
                        if (value != null) {
                            sumUpAll.getAndAdd(Long.parseLong(value.toString()));
                            cnt.countDown();
                        }
                    };
                }.attach();
                mapUid2EquityListener.put(uid, el);
            }
        }
        if (logger.isDebugEnabled()) {
            logger.debug("Waitung for countdown..");
        }
        try {
            final boolean allGood = cnt.await(10, TimeUnit.SECONDS);
            if (allGood) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Done waiting, " + uid + " owns " + sumUpAll.get() + " equity");
                }
            } else {
                if (logger.isWarnEnabled()) {
                    logger.warn("Waiting for read operations ran into timeout");
                }
            }
        } catch (final InterruptedException e) {
            if (logger.isErrorEnabled()) {
                logger.error(e.getLocalizedMessage(), e);
            }
        }

    }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X