В моем приложении флаттера у меня есть несколько вложенных Future
заданий для выполнения. Например, мне сначала нужно получить электронную почту текущего пользователя из Firebase, а затем на основе полученной электронной почты выбрать нужного пользователя из базы данных.
Это я реализовал ниже
class LoadSellAdsUIState extends State<LoadSellAdsUI> {
FirebaseUser firebaseUser;
User user;
bool startUILoad=false;
@override
void initState() {
// TODO: implement initState
super.initState();
Future.wait([
FirebaseJobs.getCurrentUser().then((firebaseUserTemp) {
if (firebaseUserTemp != null) {
firebaseUser = firebaseUserTemp;
DataFetch()
.loadUser(AppNavigation.getAPIUrl() +"user/getUserByEmail/" +firebaseUser.email)
.then((User userTemp) {
if (user!=null)
{
user = userTemp;
print(user.email + " : " + user.iduser.toString());
}
setState(() {
startUILoad=true;
});
});
}
})
]);
}
//other code here
}
Мои Future
определены в другом классе, ниже приведен код вышеупомянутых Future
static final FirebaseAuth _auth = FirebaseAuth.instance;
static Future<FirebaseUser> getCurrentUser()
{
return _auth.currentUser();
}
Future<User> loadUser(String url) async {
final response = await http.get(url);
if (response.statusCode == 200) {
return User.fromJson(convert.json.decode(response.body));
} else {
throw Exception('Failed to load post');
}
}
Обратите внимание, что я использую Future
внутри метода initState
.
Проблема в том, что код никогда не ждет внутреннего Future
(DataFetch().loadUser()
)) и всегда переходит к методу build
.
Как я могу решить эту проблему?
@pskink: Я заметил, что без этого даже код не останавливается на первом Future
!
так FirebaseJobs.getCurrentUser().then(...)
уволен? я имею в виду then(...)
@pskink: Без Future.wait
? Да, но после того, как пользовательский интерфейс загружен, пользовательский интерфейс генерирует исключения, потому что у него нет данных для работы.
исключения? какие исключения? этот: throw Exception('Failed to load post');
?
@pskink: нулевые исключения. адрес электронной почты равен нулю, идентификатор пользователя равен нулю и так далее. Это данные, которые я собираю с помощью этих Future
хорошо, я до сих пор не знаю, чего вы хотите достичь с помощью Future.wait
- если вы хотите связать несколько Future
s, это, как вы это делаете
@pskink: Как я уже упоминал, без Future.wait
кода в initState
не ждите его завершения. Вместо этого он переходит к методу build
, в то время как Future
все еще работает. Каким-то образом Future.wait
удалось остановить это на 1-е будущее.
это всегда идет к методу build
- вы не можете его остановить - вместо этого используйте FutureBuilder
@pskink: Вы имеете в виду, что он отправляется в build
, не дожидаясь фьючерсов, перечисленных в initState
?
Добавьте немного print()
в начало и конец и смотрите логи
@pskink: я только что решил проблему с помощью логического значения для отслеживания состояния Future
. Нет, я серьезно, в жизненном цикле Flutter может ли build
запускаться, даже не дожидаясь Future
в initState
? Я знаю, что initState
сработает первым, но я спрашиваю об этом ожидании...
вам не нужны boolean
- просто используйте FutureBuilder
- и да, я тоже серьезно: добавьте это в метод initState()
: var f0 = Future.delayed(Duration(seconds: 3), () { print('this will show after 3 seconds'); return 33; }); var f1 = Future.delayed(Duration(seconds: 5), () { print('this will show after 5 seconds'); return 55; }); print('start of Future.wait'); Future.wait([f0, f1]).then((_) => print('result of Future.wait: $_')); print('end of Future.wait');
Итак, вы запустили код, который я разместил? если да, то что вы видели?
Я решил эту проблему с помощью логического значения для отслеживания состояний Future
. Код ниже
@override
void initState() {
// TODO: implement initState
super.initState();
//IF THE USER IS NOT LOGGED IN, DIRECT THE USER TO LOGIN
FirebaseJobs.getCurrentUser().then((firebaseUser){
if (firebaseUser==null)
{
setState(() {
startUILoad=true;
});
}
else{
firebaseUser1 = firebaseUser;
DataFetch().loadUser(AppNavigation.getAPIUrl()+"user/getUserByEmail/"+firebaseUser.email).then((User result)
{
user = result;
setState(() {
startUILoad=true;
});
});
}
});
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return startUILoad? sellAdFutureBuilder() : Center(child: CircularProgressIndicator(),);
}
нет, вам не нужен никакой флаг - вместо этого используйте FutureBuilder
@pskink: FutureBuilder — это Widget
, и для его выполнения требуется дерево виджетов. Не так ли?
FutureBuilder
— это конструктор, который строит дерево виджетов.
для чего вам нужен
Future.wait
? просто используйтеFirebaseJobs.getCurrentUser().then(...)