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