# #flutter #dart #google-cloud-firestore #google-signin #flutter-futurebuilder
Вопрос:
Когда пользователь регистрируется в первый раз, я хочу, чтобы он получил собственный документ firestore с некоторыми данными. Эти данные я хочу показать на главном экране, но я получаю сообщение об ошибке, что данных еще нет. После горячей перезагрузки данные есть, поэтому проблема в том, что рабочий стол отображается до того, как данные будут извлечены из firestore, хотя я использую a FutureBuilder
. У меня эта проблема возникает только тогда, когда пользователь входит в систему в первый раз.
class GoogleSignInProvider extends ChangeNotifier {
final googleSignIn = GoogleSignIn();
GoogleSignInAccount _user;
GoogleSignInAccount get user => _user;
Future googleLogin() async {
try {
final googleUser = await googleSignIn.signIn();
if (googleUser == null) return;
_user = googleUser;
final googleAuth = await googleUser.authentication;
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
await FirebaseAuth.instance.signInWithCredential(credential);
await getUserData();
} catch (e) {
print(e.toString());
}
notifyListeners();
}
Future getUserData() async {
final myUser = FirebaseAuth.instance.currentUser;
bool userExist = await checkIfUserExists(myUser.uid);
if (userExist == false) {
print('User dont exist');
await FirebaseFirestore.instance.collection('users').doc(myUser.uid).set({
"email": myUser.email,
"plans": [],
"userScore": "100",
});
} else {
print('User exist');
}
/// Save userData from firestore in a Helper class which is shown on the homescreen
var userData = FirebaseFirestore.instance.collection('users').doc(myUser.uid);
return FutureBuilder(
future: userData.get(),
builder: (context, userDataSnapshot) {
if (userDataSnapshot.data == ConnectionState.done) {
var value = userDataSnapshot.data;
UserManager.userdata = value.data(); //static class where userData is stored
return null;
} else {
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
});
}
Future<bool> checkIfUserExists(String uid) async {
try {
var collectionRef = FirebaseFirestore.instance.collection('users');
var doc = await collectionRef.doc(uid).get();
return doc.exists;
} catch (e) {
throw e;
}
}
Редактировать
Это кнопка, с помощью которой пользователь может войти в систему
ElevatedButton.icon(
onPressed: () {
final provider = Provider.of<GoogleSignInProvider>(context, listen: false);
provider.googleLogin();
},
icon: Icon(MdiIcons.google),
label: Text(
'Sign In with Google',
style: TextStyle(fontSize: 16),
),
),
Ответ №1:
Проблема здесь в том, что FutureBuilder-это виджет, он не должен использоваться в функции для ожидания завершения будущего, но в другом виджете, чтобы иметь обратные вызовы при завершении и изменять отображение на основе этого.
Если не визуализировать, FutureBuilder не будет ничего делать, кроме как создавать экземпляры и занимать память.
Вероятно, вам следует изменить свой код как таковой:
...
/// Save userData from firestore in a Helper class which is shown on the homescreen
var userData = await FirebaseFirestore.instance.collection('users').doc(myUser.uid).get();
UserManager.userdata = userData.data();
...
Если вы хотите добавить циркуляр на главном экране, это можно сделать, связавшись с вашим провайдером каким-либо образом.
Комментарии:
1. Этот способ также не работает, есть ли другие проблемы в моем коде?
2. Не могли бы вы также добавить код, в котором вы используете этого провайдера?
3. Я добавил код
4. Итак, я предполагаю, что вы где-то используете поставщик-определитель изменений. Обратный вызов построителя этого объекта-это место, где вы должны получать обновленный объект после входа в систему. Там вы должны проверить, имеет ли пользовательская переменная значение.
5. Вы можете следовать этому руководству: medium.com/@aruny3/…