Je souhaite charger les informations de profil utilisateur à partir de Firestore après la connexion de l'utilisateur et je souhaite que ces données soient disponibles pour l'ensemble de l'application lorsque les données sont connectées. Je prévois de faire la dernière partie en utilisant des widgets hérités dans Flutter. Je peux charger correctement les données de Firestore et obtenir toutes les données, mais la page d'accueil n'attend pas le chargement des données avant de continuer, donc j'obtiens des erreurs. Il appelle la méthode, puis ignore la partie d'attente de la méthode et continue, donc j'obtiens des erreurs, puis après les erreurs, j'obtiens les messages de données que les données ont chargés.
J'ai essayé plusieurs choses. J'ai tout mon code de gestion des utilisateurs (connexion, inscription, ...) dans un fichier et j'ai écrit une méthode getuserProfie ()
dans ce fichier. La méthode obtient toutes les données, remplit un modèle utilisateur avec les données et renvoie ce modèle. Voir le code ci-dessous.
@override void initState() { Usermode user = UserManagement().getUserProfile(); //Calling the method super.initState(); }
J'appelle ensuite cette méthode dans ma page d'accueil comme suit
getUserProfile() async { UserModel theUser; await FirebaseAuth.instance.currentUser().then((user) { Firestore.instance .collection('/users') .where('uid', isEqualTo: user.uid) .snapshots() .listen((data) { print('getting data'); theUser = new UserModel(user.uid, data.documents[0]['email'],); print('got data'); print(theUser.email); return theUser; }); }).catchError((e) { print("there was an error"); print(e); }); }
Cela appelle la méthode très bien et obtient tout les données mais le programme n'attend pas que les données soient obtenues pour continuer. J'ai essayé de déplacer le code qui récupère les données dans la méthode initState ()
et d'appeler super.initState ()
quand j'étais sûr qu'il y avait une valeur mais cela n'a pas fonctionné. J'ai également essayé d'appeler getUserProfile ()
avant d'appeler super.initstate ()
mais cela n'a pas fonctionné.
J'ai essayé d'ajouter async à l'en-tête initState ()
mais flutter n'aime pas ça. Je peux obtenir les données de Firebase très bien, mais faire attendre le programme jusqu'à ce que les données soient obtenues est le problème que j'ai. On dirait que l'utilisation de await et async ne fonctionne pas. Avez-vous d'autres suggestions pour vous assurer que les données sont chargées avant de continuer? J'ai pensé à utiliser FutureBuilder
mais je ne sais pas comment cela fonctionnerait dans ce cas.
3 Réponses :
Puisque getUserProfile
est async
, vous devrez utiliser await
lors de son appel:
@override void initState() async { Usermode user = await UserManagement().getUserProfile(); super.initState(); }
p>
Cela n'a pas fonctionné. J'ai eu une erreur comme celle-ci: thepage.initState () a renvoyé un Future. flutter: State.initState () doit être une méthode void sans mot clé async
. flutter: Plutôt que d'attendre un travail asynchrone directement dans initState,
Ah ok. Et c'est ce que vous avez essayé de faire je suppose. J'espère que quelqu'un d'autre connaîtra une solution dans ce cas.
initState ()
ne peut pas être une fonction asynchrone
.
Ce que vous pouvez essayer est - Déplacez Usermode user = wait UserManagement (). getUserProfile ();
à une nouvelle fonction async
.
@override Widget build(BuildContext context) { if (user != null) { return ProfilePage(); } else { return CircularProgressIndicator(); }
et dans la méthode de construction, vous pouvez vérifier la valeur de l'utilisateur puis passer les widgets.
Usermode user; @override void initState() { super.initState(); _getUser(); } Void _getUser() async { user = await UserManagement().getUserProfile(); setState(() {}); }
Désormais, chaque fois que les données utilisateur sont chargées, elles appelleront setState ()
et votre page de profil se chargera.
Pour cela vous devez créer - Usermode user;
variable d'état.
Après avoir fait beaucoup de recherches, j'ai fini par utiliser Flutter StreamBuilder
. C'était parfait pour ce pour quoi je voulais l'utiliser. J'appelle la méthode UserManagement (). GetUserProfile ()
et j'obtiens l'instantané des données à partir de la valeur retournée. Si les données sont en cours de chargement, j'affiche le CircularProgressIndicator ()
. Si l'instantané est nul, j'affiche un message d'erreur. Voir l'extrait de code ci-dessous.
@override Widget build(BuildContext context) { return StreamBuilder( stream: UserManagement().getClientProfile(curUserID).snapshots(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.active) { UserModel _user = new UserModel.from(snapshot.data) return Scaffold( body: Column( crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Text(_usermodel.name), ], }); }else if (snapshot.connectionState == ConnectionState.waiting) { return Container(child: Center(child: CircularProgressIndicator())); } else { return Container( child: Column( children: <Widget>[ Padding( padding: const EdgeInsets.all(8.0), child: Icon(Icons.warning), ), Text('There was an error please try again') ], ), ); } }
Dans cet exemple, j'utilise StreamBuilder
mais vous pouvez également utiliser FutureBuilder
. StreamBuilder
écoute les modifications des données et met à jour l'interface utilisateur en conséquence tandis que FutureBuilder
obtient les données une fois jusqu'à ce que la page soit à nouveau chargée. J'ai dû apporter des modifications à mon UserModel
et j'ai également ajusté la façon dont je stockais mes données, mais tout a fonctionné. J'ai obtenu la plupart de ma solution de ici a >
Vous pouvez appeler la fonction async à partir de la méthode initState et lors de l'appel de méthode setState à partir de la méthode async et vous pouvez vérifier la valeur de l'objet dans la méthode de construction du widget