Флаттер: будущее внутри другого будущего

В моем приложении флаттера у меня есть несколько вложенных 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.

Как я могу решить эту проблему?

для чего вам нужен Future.wait? просто используйте FirebaseJobs.getCurrentUser().then(...)

pskink 10.04.2019 20:57

@pskink: Я заметил, что без этого даже код не останавливается на первом Future !

PeakGen 10.04.2019 20:58

так FirebaseJobs.getCurrentUser().then(...) уволен? я имею в виду then(...)

pskink 10.04.2019 21:00

@pskink: Без Future.wait? Да, но после того, как пользовательский интерфейс загружен, пользовательский интерфейс генерирует исключения, потому что у него нет данных для работы.

PeakGen 10.04.2019 21:01

исключения? какие исключения? этот: throw Exception('Failed to load post');?

pskink 10.04.2019 21:05

@pskink: нулевые исключения. адрес электронной почты равен нулю, идентификатор пользователя равен нулю и так далее. Это данные, которые я собираю с помощью этих Future

PeakGen 10.04.2019 21:06

хорошо, я до сих пор не знаю, чего вы хотите достичь с помощью Future.wait - если вы хотите связать несколько Futures, это, как вы это делаете

pskink 10.04.2019 21:08

@pskink: Как я уже упоминал, без Future.wait кода в initState не ждите его завершения. Вместо этого он переходит к методу build, в то время как Future все еще работает. Каким-то образом Future.wait удалось остановить это на 1-е будущее.

PeakGen 10.04.2019 21:12

это всегда идет к методу build - вы не можете его остановить - вместо этого используйте FutureBuilder

pskink 10.04.2019 21:29

@pskink: Вы имеете в виду, что он отправляется в build, не дожидаясь фьючерсов, перечисленных в initState?

PeakGen 10.04.2019 21:37

Добавьте немного print() в начало и конец и смотрите логи

pskink 10.04.2019 21:40

@pskink: я только что решил проблему с помощью логического значения для отслеживания состояния Future. Нет, я серьезно, в жизненном цикле Flutter может ли build запускаться, даже не дожидаясь Future в initState? Я знаю, что initState сработает первым, но я спрашиваю об этом ожидании...

PeakGen 10.04.2019 21:44

вам не нужны 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');

pskink 10.04.2019 22:10

Итак, вы запустили код, который я разместил? если да, то что вы видели?

pskink 11.04.2019 07:39
2
14
1 991
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я решил эту проблему с помощью логического значения для отслеживания состояний 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 11.04.2019 07:50

@pskink: FutureBuilder — это Widget, и для его выполнения требуется дерево виджетов. Не так ли?

PeakGen 11.04.2019 12:11
FutureBuilder — это конструктор, который строит дерево виджетов.
pskink 12.04.2019 08:45

Другие вопросы по теме