在导航器弹出窗口上引发错误,直到:“!_debugLocked':不正确。”

时间:2019-04-10 17:59:28

标签: dart flutter navigator

通过单击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;
    }
  }
}

错误:

  

══╡小工具库引起的异常CA ═════════════════════   I / flutter(24830):构建Navigator- [GlobalObjectKey]时引发了以下断言   I / flutter(24830):_WidgetsAppState#90d1f](脏,状态:NavigatorState#6b2b6(股票代码:跟踪1个股票)):   I / flutter(24830):'package:flutter / src / widgets / navigator.dart':断言失败:1995行pos 12:'!_debugLocked':   I / flutter(24830):不是。   I / flutter(24830):要么断言表明框架本身有错误,要么我们应该提供   I / flutter(24830):此错误消息中的更多信息可帮助您确定和解决根本原因。   I / flutter(24830):无论哪种情况,请通过在GitHub上提交错误来报告此断言:   I / flutter(24830):full list here   I / flutter(24830):引发异常时,这是堆栈:

9 个答案:

答案 0 :(得分:12)

对于那些在构建过程中调用 Navigator 的人。我发现它会间歇性地在 debugLocked

上抛出断言错误

我通过用 addPostFrameCallback 包装避免了这个问题:

WidgetsBinding.instance.addPostFrameCallback((_) {
  Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => MyPage()));
});

答案 1 :(得分:3)

我也遇到类似的错误,例如一个对话框,其中有一个注销按钮,按下该按钮会进入登录屏幕,但是发生_debugLocked错误,因此我使用了

Navigator.of(context).pushNamedAndRemoveUntil('/screen4', (Route<dynamic> route) => false);

这将删除堆栈中的所有路由,以便用户注销后无法返回到先前的路由。

设置(Route<dynamic> route) => false将确保删除推送路由之前的所有路由。

我不知道这是否是“真正的”解决方案,但是它对Flutter的初学者有所帮助。

答案 2 :(得分:2)

我也遇到了同样的问题,任何答案都对我不起作用,而且此错误也不能解释任何事情。

浏览完每行代码后,我发现我们无法在这样的构建方法中启动任何state

 @override
 Widget build(BuildContext context) {
     var viewmodel = Provider.of<ViewModel>(context);
     Navigator.of(context).push(MaterialPageRoute(builder: 
        (context)=>CreateItemPage(viewmodel.catalogData))); // this is way i was getting error.

return Scaffold();
}

由于该行,我在CreateItemPage屏幕上遇到错误。

此问题的解决方案创建button,将其称为Navigator.of(context).push(MaterialPageRoute(builder: (context)=>CreateItemPage(viewmodel.catalogData)));

答案 3 :(得分:2)

对我来说,它即将来临是因为我创建了一个推动循环,导致了此错误。 例如,

在初始路由 const dispatch = useDispatch() const handleChange = (e, user) => { dispatch({ type: 'UPDATE_USER', data: { ...user, name: e.target.value }, }) 中,代码正在推送/loading

/home

class _LoadingState extends State<Loading> { void getTime() async { // DO SOME STUFF HERE Navigator.pushNamed(context, '/home'); } @override void initState() { super.initState(); getTime(); } 的initState中,我正在推动/home创建一个循环。

/loading

答案 4 :(得分:1)

添加一些延迟然后尝试这样做您的问题将得到解决:

  Future.delayed(const Duration(milliseconds: 500), () {

//这里你可以写你的代码

        setState(() {
          Navigator.of(context).pushAndRemoveUntil(
              MaterialPageRoute(builder: (context) => SetCategory()),
              (route) => false);
        });
      });

答案 5 :(得分:0)

我不会带给您直接答案,而是带您了解问题时的想法,以期将来对您有所帮助。

让我们看看断言。它说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完成之后。

这变得非常简单-有两种方法可以做到这一点。简单的方法是只使用延迟为零的延迟将来,一旦当前调用堆栈返回到事件循环,它将使飞镖尽快安排调用:

Future.delayed(Duration.zero, () {
  Navigator. ...
});

另一种更为扑朔迷离的方法是在当前的构建/渲染周期完成后,使用调度程序来调度调用:

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

任何一种方法都可以消除您遇到的问题。

尽管如此,另一个选项也是可能的-在ExtendedPloatingActionButton中调用pop的位置:

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

您可以直接调用Navigator.of(context).popUntil...。这将消除在调用bottomSheet.closed之后执行任何操作的需要。但是,根据您逻辑中可能需要做或不需要做的其他事情,这可能不是理想的选择(我可以肯定地看到了问题,使底部表单对页面的主要部分进行了更改,以及为什么要做试图使这种情况发生在页面的逻辑中。

此外,在编写代码时,我强烈建议 将其分成小部件-例如,底页应该是其自己的小部件。构建功能越多,遵循起来就越困难,并且实际上也会对性能产生影响。您还应该尽可能避免使用GlobalKey实例-通常,如果仅通过几层,则可以向下传递对象(或回调),使用.of(context)模式或使用继承的小部件。

答案 6 :(得分:0)

在简历中,您只需要将其从initState中删除。 我建议使用AfterLayout和在 afterFirstLayout您可以将其重定向到所需的页面。这样可以保证在路由之前一切都很好。

请参阅以下步骤: 添加到pubspec:after_layout:^ 1.0.7 + 2

然后,将其扩展到要使用的类。就我而言,是一个名为HomePage的全状态小部件。因此,它看起来像:

class HomePage extends StatefulWidget {
  @override
  HomePageState createState() => HomePageState();
} //no changes here


class HomePageState extends State<HomePage> with AfterLayoutMixin<HomePage> {
//the with AfterLayoutMixin<pageName> is the only thing you need to change.

现在,您需要实现一个名为afterlayout的方法,该方法将在构建完成后执行。

@override
  Future<void> afterFirstLayout(BuildContext context) {

  //your code here safetly
}

您可以在此处找到信息: https://pub.dev/packages/after_layout

答案 7 :(得分:0)

对于那些仍然有同样问题的人,这有助于我解决它。

navigationService.popUntil((_) => true);
navigationService.navigateTo(
  'authentication',
);

基本上我等到导航完成设置一切,然后调用navigateTo。

答案 8 :(得分:-1)

在您的班级中添加此内容。

final GlobalKey<ScaffoldState> _globalKey = GlobalKey();
// ...

Scaffold(
  key: _globalKey,
  ...
)

现在,当您想向后导航时,只需使用

final bottomSheet = _globalKey.currentState.showBottomSheet(
      (context) {
    return Container(
      height: 72.0,
      child: FlatButton(
        child: Text("ORDER DETAILS"),
        onPressed: () {
          Navigator.of(context).pop();
        },
      ),
    );
  },
);
bottomSheet.closed.then((v) {
  Navigator.of(context)
      .popUntil((r) => r.settings.isInitialRoute);
});