Как реализовать стандартное поведение для виджета - PullRequest
0 голосов
/ 11 апреля 2019

Я хочу обратиться к следующему сценарию:

Экран / виджет отображается (нажат). Этот экран должен:

  • выполнить долгое задание (запрос) при первом его создании
  • показать загрузку при выполнении задачи (запрос)
  • при необходимости отобразить диалоговое окно с ошибкой (неудачный запрос)
  • обновить список соответствующим образом после завершения задачи
  • есть внешний триггер для обновления и перезапуска длинной задачи (запрос данных снова + загрузка и оповещения включены)

--------------------------

Я пришел к выводу, что вы не можете иметь такое поведение без:

  • механизм задержки для отображения диалога об ошибках (addPostFrameCallback или Future.delayed)
  • механизм состояния для обработки поведения компонента (начальная / загрузка / не загрузка / завершена)

Стоит отметить, что флаттер для меня новый, и мне может не хватать важной информации о фреймворке.

--------------------------

Вот причины для приведенных выше выводов.

Ограничение диалогового окна ошибки:

  • из метода сборки вы не можете отобразить диалоговое окно, потому что вам нужно сначала вернуть виджет (учитывая, например, что задача не выполнена, вам нужно показать диалоговое окно); в противном случае появится сообщение об ошибке

// ... // flutter: setState () или markNeedsBuild () вызывается во время сборки. // flutter: этот виджет Overlay нельзя пометить как необходимый для сборки, потому что фреймворк уже находится в // setState () или markNeedstoBuild () // ...

  • если вы выполнили задачу до того, как метод сборки потерпит неудачу, у вас снова будет та же ошибка // ... // flutter: inheritFromWidgetOfExactType (_LocalizationsScope) или inheritFromElement () был вызван ранее // flutter: _VacationsViewState.initState () завершено. // ...

  • задача не может быть запущена методом построения, поскольку этот метод вызывается много раз.

Ограничение индикатора состояния:

  • после того, как компонент виджета был создан, если задача запускалась для повторного выполнения, у компонента не будет никакой возможности узнать, что ему нужно отображать индикатор загрузки, если у него нет этого механизма состояния. Этот механизм состояний подразумевает вызов setState или использование построителей потоков (в зависимости от состояния).

--------------------------

Дополнительные фрагменты, иллюстрирующие следующие ситуации:

// using FutureBuilder
Widget build(BuildContext context) {
    return FutureBuilder(
    future: someFuture,
    builder: (BuildContext context, AsyncSnapshot snapshot) {
        // Here we need to display loading while task is not finished and a dialog if it fails
        // dialog needs to be performed with a delay
        // triggering again the build will need to have a setState called to “reload”
    });
}

// using StreamBuilder
Widget build(BuildContext context) {
    return StreamBuilder<void>(
        stream: status,
        builder: (BuildContext context, AsyncSnapshot<void> status) {
           //  status can represent states (loading/finished/… )
       // dialog needs to be displayed with a delay in case the error the current state
    });
}

--------------------------

Достигнут окончательный компромисс:

  • использовать некоторый механизм состояний с дескриптором состояния и, возможно, потоком или использовать setState напрямую
  • использовать механизм задержки для диалогов

--------------------------

1 Ответ

0 голосов
/ 15 апреля 2019

Я не могу попробовать это на самом деле, но разве что-то не поможет решить вашу проблему?

Что не так с использованием setState?

Future _calculation;

initState(){
  super.initState();
  _calculation = fetchData();
}


  FutureBuilder<String>(
  future: _calculation, // a previously-obtained Future<String> or null
  builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
    switch (snapshot.connectionState) {
      case ConnectionState.none:
        return Text('Press button to start.');
      case ConnectionState.active:
      case ConnectionState.waiting:
        return Text('Awaiting result...');
      case ConnectionState.done:
        if (snapshot.hasError)
          //show your error dialog

          // show result
        return Text('Result: ${snapshot.data}');
    }
    return null; // unreachable
  },
);

  new RaisedButton(
  child: const Text('Reload'),
  color: Theme.of(context).accentColor,
  elevation: 4.0,
  splashColor: Colors.blueGrey,
  onPressed: () {
    setState((
      // this will trigger the FutureBuilder and update/show the result
      _calculation = fetchData();
    ));
  },
),
...