C'est un problème classique des API Web asynchrones. Vous ne pouvez pas renvoyer maintenant quelque chose qui n'a pas encore été chargé. En d'autres termes, vous ne pouvez pas simplement créer une variable globale et l'utiliser en dehors de l'API. onDataChange()
car il sera toujours null
. Cela se produit parce que onDataChange()
est dite asynchrone. Selon la vitesse de votre connexion et l'état, il peut s'écouler de quelques centaines de millisecondes à quelques secondes avant que ces données soient disponibles.
Mais non seulement Firebase Realtime Database charge les données de manière asynchrone, mais presque toutes les API Web modernes le font aussi, car cela peut prendre un certain temps. Ainsi, au lieu d'attendre les données (ce qui peut conduire à des dialogues d'application non réactifs pour vos utilisateurs), le code de votre application principale continue pendant que les données sont chargées sur un thread secondaire. Ensuite, lorsque les données sont disponibles, votre méthode onDataChange() est appelée et peut utiliser les données. En d'autres termes, au moment où onDataChange()
est appelée, vos données ne sont pas encore chargées.
Prenons un exemple, en plaçant quelques déclarations de journal dans le code, pour voir plus clairement ce qui se passe.
private String getUserName(String uid) {
Log.d("TAG", "Before attaching the listener!");
databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// How to return this value?
dataSnapshot.getValue(String.class);
Log.d("TAG", "Inside onDataChange() method!");
}
@Override
public void onCancelled(DatabaseError databaseError) {}
});
Log.d("TAG", "After attaching the listener!");
}
Si nous exécutons ce code, la sortie sera :
Avant d'attacher l'écouteur !
Après avoir attaché l'écouteur !
Dans la méthode onDataChange() !
Ce n'est probablement pas ce que vous attendiez, mais cela explique précisément pourquoi vos données sont null
lors de son retour.
La première réaction de la plupart des développeurs est d'essayer de "réparer" ce problème. asynchronous behavior
Je vous le déconseille personnellement. Le web est asynchrone, et plus vite vous l'accepterez, plus vite vous pourrez apprendre à devenir productif avec les API web modernes.
J'ai trouvé qu'il était plus facile de recadrer les problèmes pour ce paradigme asynchrone. Au lieu de dire "D'abord obtenir les données, puis les enregistrer", je formule le problème comme suit : "Commencer à obtenir les données. Lorsque les données sont chargées, enregistrez-les". Cela signifie que tout code qui requiert les données doit se trouver à l'intérieur de onDataChange()
ou appelé depuis l'intérieur, comme ceci :
databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// How to return this value?
if(dataSnapshot != null) {
System.out.println(dataSnapshot.getValue(String.class));
}
}
@Override
public void onCancelled(DatabaseError databaseError) {}
});
Si vous voulez l'utiliser en dehors, il existe une autre approche. Vous devez créer votre propre callback pour attendre que Firebase vous renvoie les données. Pour ce faire, vous devez tout d'abord créer un objet interface
comme ça :
public interface MyCallback {
void onCallback(String value);
}
Ensuite, vous devez créer une méthode qui récupère réellement les données de la base de données. Cette méthode doit ressembler à ceci :
public void readData(MyCallback myCallback) {
databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
String value = dataSnapshot.getValue(String.class);
myCallback.onCallback(value);
}
@Override
public void onCancelled(DatabaseError databaseError) {}
});
}
À la fin, il suffit d'appeler readData()
et passe une instance de la méthode MyCallback
comme argument lorsque vous en avez besoin comme ceci :
readData(new MyCallback() {
@Override
public void onCallback(String value) {
Log.d("TAG", value);
}
});
C'est la seule façon d'utiliser cette valeur en dehors de l'Union européenne. onDataChange()
méthode. Pour plus d'informations, vous pouvez également consulter le site suivant vidéo .
Editar: 26 février 2021
Pour plus d'informations, vous pouvez consulter l'article suivant :
Et la vidéo suivante :
1 votes
Comme @PeterHaddad l'a mentionné, la méthode onDataChange est asynchrone, ce qui signifie qu'elle renverra toujours null. Puis-je demander : pourquoi avez-vous besoin de retourner le nom de l'utilisateur ? Pourquoi ne pas simplement utiliser ce nom dans la méthode onDataChange ?
2 votes
Comme l'a dit @PeterHaddad, parce que
onDataChange()
est appelée asynchrone, cela ne fonctionnera pas. Veuillez consulter ma réponse.1 votes
Lisez ceci pour comprendre pourquoi les API de Firebase sont asynchrones : medium.com/@CodingDoug/
0 votes
Lisez ceci pour comprendre comment résoudre le problème de la base de données asynchrone avec une ou plusieurs références à la base de données : stackoverflow.com/questions/48720701/