Флаттер: Строитель дважды вызывает будущего строителя, когда я выбрасываю исключение - PullRequest
0 голосов
/ 30 апреля 2020

Я пытаюсь использовать панель закусок на моем будущем сборщике, чтобы показать ошибку. Так что после создания моего будущего экземпляра метода на метод initState:

Future<DetailModel> futureDetail;
  ...
   @override
  void initState() {
    futureDetail =
        DetailProvider().detailProvider(widget.id);
    super.initState();
  }

В futureBuilder я использую как показано ниже:

Center(
              child: SingleChildScrollView(
                child: FutureBuilder(
                  future: futureDetail,
                  builder:
                      (context, AsyncSnapshot<DetailProductModel> snapshot) {
                    if (!snapshot.hasError ||
                        snapshot.connectionState == ConnectionState.waiting) {
                      return Center(
                        child: CircularProgressIndicator(),
                      );
                    }
                    if (snapshot.hasData && snapshot.data.data != null) {
                      return Container();
                    }
                    if (snapshot.hasError &&
                        snapshot.error != null &&
                        snapshot.data == null) {
                      WidgetsBinding.instance.addPostFrameCallback((_) =>
                          showSnackbar(snapshot.error.toString(), context));
                      return Container();
                    } else {
                      return Center(
                        child: Text('failed to load'),
                      );
                    }
                  },
                ),
              ),
            ),

detailProvider метод вызывает службу http, и в моем примере я выкидываю SocketException, чтобы получить ошибку на компоновщике и показывать снэкбар. хотите показать snakbar.

Но дважды вызывается строитель, а в снэк-баре дважды появляется ошибка? Я проверил, что эти три условия одинаковы snapshot.hasError and snapshot.error != null and snapshot.data == null в двойной сборке. Как я могу предотвратить показ дважды в Snakbar?

1 Ответ

1 голос
/ 30 апреля 2020

Обновление: Возникла проблема с кодом, которым я поделился. Пожалуйста, проверьте это.

Прежде всего, всегда создавайте свой SnackBar вне FutureBuilder, потому что FutureBuilder постоянно вызывается, поэтому он вызывает бесконечное l oop. Что вы можете сделать, это использовать catchError. Вы все еще можете проверить, есть ли активный SnackBar, прежде чем создавать новый, используя переменную, которую мы уже объявили.

Вы увидите, что SnackBar будет отображаться только один раз, хотя я трижды вызывал его при запуске код ниже.

Примените тот же способ, чтобы обновить свой собственный код:

class App extends StatefulWidget {
  @override
  _AppState createState() => _AppState();
}

class _AppState extends State<App> {
  bool snackBarActive = false;
  Future<String> futureDetail;

  @override
  void initState() {
    futureDetail = Future<String>.error('An error Occurred').catchError((errText) {
      showSnackBar(errText);
      showSnackBar(errText);
      showSnackBar(errText);
    });
    super.initState();
  }

  void showSnackBar(String errText) {
    if (!snackBarActive) {
      setState(() {
        snackBarActive = true;
      });

      WidgetsBinding.instance.addPostFrameCallback((_) => Scaffold.of(context)
              .showSnackBar(SnackBar(
                content: Text(errText),
              ))
              .closed
              .whenComplete(() {
            setState(() {
              snackBarActive = false;
            });
          }));
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: SingleChildScrollView(
          child: FutureBuilder(
            future: futureDetail,
            builder: (context, AsyncSnapshot<String> snapshot) {
              if (!snapshot.hasError &&
                  snapshot.hasData &&
                  snapshot.data != null) {
                return Container();
              } else {
                return Center(
                  child: Text('failed to load'),
                );
              }
            },
          ),
        ),
      ),
    );
  }
}


...