Flutter: 当我抛出异常时,在未来的建造者中调用两次。

问题描述 投票:0回答:1

我试图在我的future builder上使用snackbar来显示错误,所以在initState方法上创建了我的future方法实例。

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 在生成器上得到错误并显示 snackbar.

我知道未来的构建器是用来显示每个状态的widget的,但是我想显示snakbar,但是构建器被调用了两次,snackbar显示了两次错误?

我检查了一下这三个条件是否相同 snapshot.hasError and snapshot.error != null and snapshot.data == null 在两次构建中,如何防止显示两次蛇形条?如何防止两次显示snakbar?

flutter flutter-layout future
1个回答
1
投票

更新了,我分享的代码有问题。 我分享的代码有问题。请检查一下这个。

首先,总是在FutureBuilder之外创建你的SnackBar,因为FutureBuilder不断被调用,所以会造成无限循环。你可以做的是使用catchError。在创建一个新的SnackBar之前,你仍然可以通过使用我们已经声明的变量来检查是否有一个活动的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'),
                );
              }
            },
          ),
        ),
      ),
    );
  }
}


© www.soinside.com 2019 - 2024. All rights reserved.