web-dev-qa-db-fra.com

attendre que firebase récupère les données

Je veux construire une méthode qui retourne une valeur child dans FireBase. J'ai essayé de faire quelque chose comme ça:

public String getMessage(){

    root.child("MessagesOnLaunch").child("Message").addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            message = (String) dataSnapshot.getValue();
            Log.i("4r398", "work");
        }

        @Override
        public void onCancelled(FirebaseError firebaseError) {
            Log.e("error", firebaseError.getMessage());
        }
    });
    return message;
}

Le problème est que la méthode retourne null c'est probablement parce que la méthode n'attend pas la fin de l'écouteur et renvoie null car c'est la valeur par défaut de message. Comment faire en sorte que cette méthode attende que l'écouteur se produise puis retourne la valeur. 

16
ben

Faire une interface

 public interface OnGetDataListener {
    //this is for callbacks
    void onSuccess(DataSnapshot dataSnapshot);
    void onStart();
    void onFailure();
}

Déclarez la fonction suivante readData ()

public void readData(Firebase ref, final OnGetDataListener listener) {
    listener.onStart();
    ref.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            listener.onSuccess(dataSnapshot);
        }

        @Override
        public void onCancelled(FirebaseError firebaseError) {
            listener.onFailure();
        }
    });

}

Appelez la fonction readData () comme suit

readData(root.child("MessagesOnLaunch").child("Message"), new OnGetDataListener() {
                @Override
                public void onSuccess(DataSnapshot dataSnapshot) {

               //got data from database....now you can use the retrieved data


                }
                @Override
                public void onStart() {
                    //when starting
                    Log.d("ONSTART", "Started");
                }

                @Override
                public void onFailure() {
                    Log.d("onFailure", "Failed");
                }
            });

readData () peut être appelé dans votre méthode getMessage () ou même dans onCreate ()

9
Joseph Varghese

Vous pouvez utiliser CountDownLatch . Voici comment vous pouvez l'utiliser.

public String getMessage(){
   CountDownLatch done = new CountDownLatch(1);
   final String message[] = {null}; 
   root.child("MessagesOnLaunch").child("Message").addListenerForSingleValueEvent(new ValueEventListener() {

    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        message[0] = (String) dataSnapshot.getValue();
        System.out.println("worked");
        done.countDown();
    }

    @Override
    public void onCancelled(FirebaseError firebaseError) {
        System.out.println("failed"+firebaseError.getMessage());
    }
});
done.await(); //it will wait till the response is received from firebase.
return message[0];
}
4
Tirupati Singh

N'utilisez pas Firebase en tant que fonctions qui renvoient des valeurs - cela va à l'encontre de sa nature asynchrone.

Planifiez une structure de code permettant à Firebase d’accomplir sa tâche, puis passez à l’étape suivante dans le bloc (blocage).

Dans votre code, par exemple, modifiez la fonction pour ne rien renvoyer et dans onDataChange, la dernière ligne appelle la fonction suivante pour mettre à jour votre interface utilisateur.

3

Je laisserai ça ici pour aider ceux qui font face au même problème que moi. @Tirupati Singh code a l'air bien mais j'ai écrit ma réponse ci-dessous sa pourquoi il n'a pas fonctionné pour moi. Utilisation du type atomique travaillé - 

public AtomicInteger getMessage(){
        final AtomicBoolean done = new AtomicBoolean(false);
        final AtomicInteger message1 = new AtomicInteger(0);

        //assuming you have already called firebase initialization code for admin sdk, Android etc
       DatabaseReference root = FirebaseDatabase.getInstance().getReference("server");
       root.child("MessagesOnLaunch").child("Message").addListenerForSingleValueEvent(new ValueEventListener() {

        public void onDataChange(DataSnapshot dataSnapshot) {
            message1.set((Integer) dataSnapshot.getValue()); 
            done.set(true);
        }

        public void onCancelled(DatabaseError error) {
            // TODO Auto-generated method stub

        }
    });
    while (!done.get());

    return message1;
}

Notez que la fonction ne peut renvoyer que le type de message Entier. Je ne pouvais pas le faire fonctionner pour String car aucun type atomique pour String. J'espère que cela t'aides!

0
Zod