web-dev-qa-db-ja.com

「!_debugLocked ':は真ではない」までナビゲーターポップでスローされるエラー。

ShowBottomSheetをクリックして他の画面に移動する画面をポップすると、このエラーは次のコードを通じてスローされます。これが発生している理由がわかりません。

class _CheckoutButtonState extends State<_CheckoutButton> {
  final GlobalKey<ScaffoldState> _globalKey = GlobalKey();
  final DateTime deliveryTime = DateTime.now().add(Duration(minutes: 30));

  final double deliveryPrice = 5.00;

  @override
  Widget build(BuildContext context) {
    SubscriptionService subscriptionService =
        Provider.of<SubscriptionService>(context);
    CheckoutService checkoutService = Provider.of<CheckoutService>(context);
    return Container(
      height: 48.0,
      width: MediaQuery.of(context).size.width * 0.75,
      child: StreamBuilder(
        stream: subscriptionService.subscription$,
        builder: (_, AsyncSnapshot<Subscription> snapshot) {
          if (!snapshot.hasData) {
            return Text("CHECKOUT");
          }
          final Subscription subscription = snapshot.data;
          final List<Order> orders = subscription.orders;
          final Package package = subscription.package;
          num discount = _getDiscount(package);
          num price = _totalPriceOf(orders, discount);
          return StreamBuilder<bool>(
              stream: checkoutService.loading$,
              initialData: false,
              builder: (context, snapshot) {
                bool loading = snapshot.data;
                return ExtendedFloatingActionButton(
                  loading: loading,
                  disabled: loading,
                  action: () async {
                    checkoutService.setLoadingStatus(true);
                    final subscription =
                        await Provider.of<SubscriptionService>(context)
                            .subscription$
                            .first;
                    try {
                      await CloudFunctions.instance.call(
                          functionName: 'createSubscription',
                          parameters: subscription.toJSON);
                      final bottomSheet =
                          _globalKey.currentState.showBottomSheet(
                        (context) {
                          return Container(
                            width: MediaQuery.of(context).size.width,
                            decoration: BoxDecoration(
                              gradient: LinearGradient(
                                begin: Alignment.topCenter,
                                end: Alignment.bottomCenter,
                                colors: [
                                  Theme.of(context).scaffoldBackgroundColor,
                                  Theme.of(context).primaryColor,
                                  Theme.of(context).primaryColor,
                                ],
                                stops: [-1.0, 0.5, 1.0],
                              ),
                            ),
                            child: Column(
                              children: <Widget>[
                                Expanded(
                                  child: Column(
                                    mainAxisAlignment: MainAxisAlignment.center,
                                    children: <Widget>[
                                      Padding(
                                        padding:
                                            const EdgeInsets.only(bottom: 16.0),
                                        child: Text(
                                          "Thank you for your order",
                                          textAlign: TextAlign.center,
                                          style: Theme.of(context)
                                              .textTheme
                                              .display1,
                                        ),
                                      ),
                                      SvgPicture.asset(
                                        'assets/images/thumb.svg',
                                        height: 120.0,
                                        width: 100.0,
                                      )
                                      // CircleAvatar(
                                      // radius: 40.0,
                                      // backgroundColor: Colors.transparent,
                                      // child: Icon(
                                      // Icons.check,
                                      // color: Theme.of(context)
                                      // .textTheme
                                      // .display1
                                      // .color,
                                      // size: 80.0,
                                      // ),
                                      // ),
                                    ],
                                  ),
                                ),
                                Container(
                                  width:
                                      MediaQuery.of(context).size.width * 0.9,
                                  height: 72.0,
                                  padding: EdgeInsets.only(bottom: 24),
                                  child: ExtendedFloatingActionButton(
                                    text: "ORDER DETAILS",
                                    action: () {
                                      Navigator.of(context).pop();
                                    },
                                  ),
                                ),
                              ],
                            ),
                          );
                        },
                      );
                      bottomSheet.closed.then((v) {
                        Navigator.of(context)
                            .popUntil((r) => r.settings.isInitialRoute);
                      });
                    } catch (e) {
                      print(e);
                      final snackBar =
                          SnackBar(content: Text('Something went wrong!'));
                      Scaffold.of(context).showSnackBar(snackBar);
                    }
                  },
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      Text(
                        "CHECKOUT ",
                        style: Theme.of(context)
                            .textTheme
                            .display4
                            .copyWith(color: Colors.white),
                      ),
                      Text(
                        "EGP " +
                            (price + (orders.length * deliveryPrice))
                                .toStringAsFixed(2),
                        style: Theme.of(context)
                            .textTheme
                            .display4
                            .copyWith(color: Theme.of(context).primaryColor),
                      ),
                    ],
                  ),
                );
              });
        },
      ),
    );
  }

  num _totalPriceOf(List<Order> orders, num discount) {
    num price = 0;
    orders.forEach((Order order) {
      List<Product> products = order.products;
      products.forEach((Product product) {
        price = price + product.price;
      });
    });
    num priceAfterDiscount = price * (1 - (discount / 100));
    return priceAfterDiscount;
  }

  num _getDiscount(Package package) {
    if (package == null) {
      return 0;
    } else {
      return package.discount;
    }
  }
}

エラー:

Wウィジェットライブラリによって引き起こされる例外╞═════════════════════════════════════════ ══════════════════I/flutter(24830):Navigator- [GlobalObjectKey I/flutter(24830)の構築時に次のアサーションがスローされました:_WidgetsAppState#90d1f](dirty、state :NavigatorState#6b2b6(tickers:1ティッカーを追跡)):I/flutter(24830): 'package:flutter/src/widgets/navigator.Dart':Failed assertion:line 1995 pos 12: '!_debugLocked':I/flutter (24830):真実ではありません。 I/flutter(24830):アサーションはフレームワーク自体のエラーを示すか、実質的にI/flutter(24830)を提供する必要があります。このエラーメッセージには、根本的な原因の特定と修正に役立つ詳細情報が含まれています。 I/flutter(24830):どちらの場合も、GitHubにバグを報告してこのアサーションを報告してください:I/flutter(24830): https://github.com/flutter/flutter/issues/new?template = BUG.md I/flutter(24830):例外がスローされたとき、これはスタックでした:

8
Aya Elsisy

直接回答するのではなく、質問を見つけたときにこれについて私がどのように考えたのかを説明します。将来的に役立つことを願っています。

アサーションを見てみましょう。 Failed assertion: line 1995 pos 12: '!_debugLocked': I/flutter (24830): is not true.と書かれています。うーん、面白い。そのコード行を見てみましょう。

assert(!_debugLocked);

まあ、それは私に多くの情報を与えません、変数を見てみましょう。

_bool _debugLocked = false; // used to prevent re-entrant calls to Push, pop, and friends_

それは良いです。これは、Pushやpopなどへの再入可能な呼び出しを防ぐためにあります(つまり、「Push」や「pop」への呼び出し内から「Push」や「pop」などを呼び出さないことを意味します)。それでは、コードまでさかのぼってみましょう。

これはおそらく犯人のようです:

_bottomSheet.closed.then((v) {
  Navigator.of(context)
    .popUntil((r) => r.settings.isInitialRoute);
});
_

ここでは手順をスキップし、代わりに演繹推論を使用します-クローズドフューチャーはpopの間に終了することに賭けています。必要に応じて、コードを読んで確認してください。

したがって、pop関数内からpopを呼び出すことが問題である場合、popが完了するまでpopの呼び出しを延期する方法を理解する必要があります。

これは非常に簡単になります。これを行うには2つの方法があります。単純な方法は、遅延ゼロの遅延フューチャを使用することです。これにより、現在のコールスタックがイベントループに戻ったら、Dartができるだけ早くコールをスケジュールします。

_Future.delayed(Duration.zero, () {
  Navigator. ...
});
_

これを行うためのもう1つのフラッターな方法は、スケジューラを使用して、現在のビルド/レンダリングサイクルの完了後に呼び出しをスケジュールすることです。

_SchedulerBinding.instance.addPostFrameCallback((_) {
  Navigator. ...
});
_

どちらの方法でも、発生している問題を解消できます。

ただし、popを​​呼び出すExtendedFloatingActionButtonで別のオプションを使用することもできます。

_ExtendedFloatingActionButton(
 text: "ORDER DETAILS",
  action: () {
    Navigator.of(context).pop();
  },
),
_

代わりに、単にNavigator.of(context).popUntil...を呼び出すこともできます。これにより、bottomSheet.closedが呼び出された後に何かを行う必要がなくなります。ただし、ロジックで実行する必要があるかどうかに応じて、これは理想的ではない可能性があります(ページのメイン部分への変更をボトムシートに設定することによる問題と、その理由ページのロジックでそれを実現しようとしました)。

また、コードを書いているとき、私はhighlyをウィジェットに分割することをお勧めします。たとえば、下部のシートは独自のウィジェットである必要があります。ビルド関数が多ければ多いほど、追跡が難しくなり、実際にパフォーマンスにも影響を与える可能性があります。また、可能な限りGlobalKeyインスタンスの使用は避けてください。通常、オブジェクト(またはコールバック)をいくつかのレイヤーのみを介して渡す場合は、.of(context)パターンを使用するか、継承されたウィジェットを使用します。

32
rmtmckenzie