通过单击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):引发异常时,这是堆栈:
答案 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);
});