Виджет Flutter FutureBuilder не отвечает на разрешение Future при связывании Futures с await

Я использую метод initState() виджета flutter для создания двух будущих целых чисел; delayed, который является простым Future.delay, и delayedAwaited, который ожидает переменной delayed и удваивает ее значение. Метод build() включает два FutureBuilder, по одному на каждое будущее. См. Пример кода ниже:

class FutureTest extends StatefulWidget {
  @override
  _FutureTestState createState() => _FutureTestState();
}

class _FutureTestState extends State<FutureTest> {
  Future<int>? delayed;
  Future<int>? delayedAwaited;

  @override
  void initState() {
    super.initState();
    initFutures();
  }

  void initFutures() async {
    delayed = Future.delayed(Duration(seconds: 2), () => 5);
    delayedAwaited = Future.value((await delayed)! * 2);
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        FutureBuilder(
          future: delayed,
          builder: (context, snapshot) => Text('delayed: ${snapshot.data}'),
        ),
        FutureBuilder(
          future: delayedAwaited,
          builder: (context, snapshot) => Text('awaited: ${snapshot.data}'),
        ),
      ],
    );
  }
}

Вот проблема: пользовательский интерфейс обновляется только для delayed, а не для delayedAwaited (он остается нулевым). Пользовательский интерфейс обновляется, чтобы отражать истинное значение при ручной перезагрузке, поэтому будущее решается правильно, но Flutter просто не запускает FutureBuilder для восстановления. Я ожидал, что пользовательский интерфейс обновится и для delayAwaited.

Смотрите поведение здесь: https://dartpad.dev/62b272db200ca39ed854be5a7183967d?null_safety=truet=ru

По какой-то причине изменение initFutures() на использование Future.delayed для обоих фьючерсов устраняет проблему, как показано здесь: https://dartpad.dev/9b386a45428046b193800351a4ade5b1?null_safety=true

Может ли кто-нибудь объяснить, почему данный код работает так, и что лучше всего подходит для достижения того, что я пытаюсь сделать.


person Elliot Sayes    schedule 16.01.2021    source источник
comment
Я предполагаю, что delayedAwaited никогда не является будущим (поскольку вы ожидаете перед ним), поэтому он переходит прямо от нуля к завершенному значению. Или что-то подобное. Избавьтесь от await и переключитесь на .then, чтобы установить delayedAwaited. Или меня может смутить ваш пример. :)   -  person Randal Schwartz    schedule 16.01.2021
comment
Насколько я понимаю, асинхронные функции устраняют необходимость использования шаблона .then. DelayAwaited должен быть немедленно установлен в будущее, поскольку я считаю, что это поведение асинхронных функций. Есть ли способ добиться этого, используя только синтаксис async / await? Источник: youtu.be/SmTCmDMi4BY?t=90   -  person Elliot Sayes    schedule 16.01.2021
comment
Определенно все еще иногда нужен синтаксис .then.   -  person Randal Schwartz    schedule 16.01.2021
comment
добавление print(delayed); print(delayedAwaited); в первую строку build() метода объяснит, почему это происходит   -  person pskink    schedule 16.01.2021
comment
@pskink, вы совершенно правы, delayedAwaited отображается как null. Есть ли способ немедленно назначить его будущему, которое зависит от другого значения будущего, используя семантику async / await?   -  person Elliot Sayes    schedule 16.01.2021


Ответы (1)


Вы можете сделать это таким образом, поскольку в комментариях вы упомянули, что хотите использовать только async / await:

 void initFutures() {
    delayed = fordelayed();
    delayedAwaited = fordelayedAwaited();
    
  }
  
  Future<int> fordelayed() async {
      return await Future.delayed(Duration(seconds: 2), () => 5);
  }
  
  Future<int> fordelayedAwaited() async {
      int fromdelayed = await fordelayed();
      return fromdelayed * 2;
  }
person Calvin Gonsalves    schedule 16.01.2021
comment
Думаю, это лучшее решение. Вы можете еще больше упростить, удалив async из initFutures(). Для краткости я выбрал следующий синтаксис: delayedAwaited = Future(() async => (await delayed)! * 2);. Шаблон состоит в том, чтобы назначать фьючерсы без прямого использования async / await, но использовать их в функциях обратного вызова (названных как ваши или анонимно как мои). - person Elliot Sayes; 17.01.2021
comment
Согласен, async от initFutures() не нужен. Буду обновлять. - person Calvin Gonsalves; 17.01.2021