我无法找到此异常的来源,而且应用程序非常复杂,因此很难显示代码的任何相关部分。这是我发生错误时的存储库: Github repo
我怀疑以下代码可能是犯罪者:
Widget buildResultCard(Map result, BuildContext context) {
String name = result["value"];
String description =
result["label"].replaceAll(new RegExp(r"<(?:.|\n)*?>"), "");
TextEditingController controller = new TextEditingController(text: name);
Function onPressed = () {
showDialog(
context: context,
child: new AlertDialog(
title: new Text("Name your schedule"),
content: new TextField(
autofocus: true,
controller: controller,
),
actions: <Widget>[
new FlatButton(
onPressed: () {
String givenName = controller.text;
ScheduleMeta schedule = new ScheduleMeta(
givenName: givenName,
name: name,
type: _selectedChoice.value,
description: description);
scheduleStore
.dispatch(new AddScheduleAction(schedule: schedule));
scheduleStore.dispatch(
new SetCurrentScheduleAction(schedule: schedule));
fetchAllSchedules(scheduleStore.state.schedules)
.then((weeks) {
scheduleStore.dispatch(
new SetWeeksForCurrentScheduleAction(weeks: weeks));
});
Scaffold.of(context).showSnackBar(new SnackBar(
content: new Text("Added " + givenName),
action: new SnackBarAction(
label: "Undo",
onPressed: () {
scheduleStore.dispatch(
new RemoveScheduleAction(schedule: name));
Scaffold.of(context).showSnackBar(new SnackBar(
content: new Text(
"Deleted " + givenName),
));
}),
));
Navigator.of(context).pop();
},
child: new Text("Add")),
],
));
};
return new Card(
child: new Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new ListTile(
leading: const Icon(Icons.schedule),
title: new Text(name),
subtitle: new Text(description),
isThreeLine: true,
dense: true,
),
new ButtonTheme.bar(
child: new ButtonBar(
children: <Widget>[
new FlatButton(
child: const Text('Add Schedule'),
onPressed: scheduleStore.state.schedules
.any((schedule) => schedule.name == name)
? null
: onPressed)
],
),
),
],
),
);
}
显示对话框时出现错误,当用户按下对话框上的按钮时,会直接相继发送两个Redux存储调度。对话框后面的UI订阅了Redux商店中的更改。
我认为Dart / Flutter是单线程的,所以不会发生这样的碰撞,看起来线程在一个小部件上调用setState(),而另一个则在小部件树上锁定。
有没有办法检查小部件树是否被锁定以便可以避免这种情况?
堆栈提供以下信息:
I/flutter (13466): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter (13466): The following assertion was thrown while finalizing the widget tree:
I/flutter (13466): setState() or markNeedsBuild() called when widget tree was locked.
I/flutter (13466): This _ModalScope widget cannot be marked as needing to build because the framework is locked.
I/flutter (13466): The widget on which setState() or markNeedsBuild() was called was:
I/flutter (13466): _ModalScope([LabeledGlobalKey<_ModalScopeState>#cb4cc]; state: _ModalScopeState#d4c02())
I/flutter (13466):
I/flutter (13466): When the exception was thrown, this was the stack:
I/flutter (13466): #0 Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:3250)
I/flutter (13466): #2 Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:3226)
I/flutter (13466): #3 State.setState (package:flutter/src/widgets/framework.dart:1072)
I/flutter (13466): #4 _ModalScopeState._routeSetState (package:flutter/src/widgets/routes.dart:473)
I/flutter (13466): #5 ModalRoute.setState (package:flutter/src/widgets/routes.dart:552)
I/flutter (13466): #6 ModalRoute.changedInternalState (package:flutter/src/widgets/routes.dart:889)
I/flutter (13466): #7 TransitionRoute&&LocalHistoryRoute.removeLocalHistoryEntry (package:flutter/src/widgets/routes.dart:317)
I/flutter (13466): #8 LocalHistoryEntry.remove (package:flutter/src/widgets/routes.dart:267)
I/flutter (13466): #9 DrawerControllerState.dispose (package:flutter/src/material/drawer.dart:147)
I/flutter (13466): #10 StatefulElement.unmount (package:flutter/src/widgets/framework.dart:3550)
I/flutter (13466): #11 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1626)
I/flutter (13466): #12 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1624)
I/flutter (13466): #13 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3427)
I/flutter (13466): #14 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1622)
I/flutter (13466): #15 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1624)
I/flutter (13466): #16 MultiChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:4421)
I/flutter (13466): #17 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1622)
I/flutter (13466): #18 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1624)
I/flutter (13466): #19 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3427)
I/flutter (13466): #20 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1622)
I/flutter (13466): #21 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1624)
I/flutter (13466): #22 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3427)
I/flutter (13466): #23 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1622)
I/flutter (13466): #24 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1624)
I/flutter (13466): #25 SingleChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:4321)
I/flutter (13466): #26 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1622)
I/flutter (13466): #27 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1624)
I/flutter (13466): #28 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3427)
I/flutter (13466): #29 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1622)
I/flutter (13466): #30 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1624)
I/flutter (13466): #31 SingleChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:4321)
I/flutter (13466): #32 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1622)
I/flutter (13466): #33 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1624)
I/flutter (13466): #34 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3427)
I/flutter (13466): #35 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1622)
I/flutter (13466): #36 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1624)
I/flutter (13466): #37 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3427)
I/flutter (13466): #38 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1622)
I/flutter (13466): #39 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1624)
I/flutter (13466): #40 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3427)
I/flutter (13466): #41 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1622)
I/flutter (13466): #42 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1624)
I/flutter (13466): #43 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3427)
I/flutter (13466): #44 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1622)
I/flutter (13466): #45 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1624)
I/flutter (13466): #46 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3427)
I/flutter (13466): #47 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1622)
I/flutter (13466): #48 _InactiveElements._unmountAll (package:flutter/src/widgets/framework.dart:1636)
I/flutter (13466): #49 BuildOwner.finalizeTree.<anonymous closure> (package:flutter/src/widgets/framework.dart:2228)
I/flutter (13466): #50 BuildOwner.lockState (package:flutter/src/widgets/framework.dart:2060)
I/flutter (13466): #51 BuildOwner.finalizeTree (package:flutter/src/widgets/framework.dart:2227)
I/flutter (13466): #52 BindingBase&SchedulerBinding&GestureBinding&ServicesBinding&RendererBinding&WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:505)
I/flutter (13466): #53 BindingBase&SchedulerBinding&GestureBinding&ServicesBinding&RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:189)
I/flutter (13466): #54 BindingBase&SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:688)
I/flutter (13466): #55 BindingBase&SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:636)
I/flutter (13466): #56 _drawFrame (file:///b/build/slave/Linux_Engine/build/src/flutter/lib/ui/hooks.dart:70)
I/flutter (13466): (elided one frame from class _AssertionError)
I/flutter (13466): ════════════════════════════════════════════════════════════════════════════════════════════════════
答案 0 :(得分:10)
这不是线程问题。此错误表示您在构建阶段正在调用setState
。
一个典型的例子如下:
Widget build(BuildContext context) {
setState(() { print("foo"); });
return Container();
}
但是setState调用可能不太明显。例如,Navigator.pop(context)
在内部执行setState
。因此,以下内容:
Widget build(BuildContext context) {
Navigator.pop(context);
return Container();
}
也不行。
看一下堆栈跟踪,似乎与Navigator.pop(context)
模态同时尝试用新数据进行更新。
答案 1 :(得分:5)
使用Scaffold
和Drawer
的特殊情况 :
如果您尝试用打开的Drawer
重建树,也可能发生这种故障。例如,如果您向Bloc
发送一条消息,要求重新构建整个页面/屏幕。
考虑首先在点击处理程序中调用Navigator.pop(context)
。
答案 2 :(得分:3)
作为解决方法,将调用setState
的代码包装到WidgetsBinding.addPostFrameCallback:
WidgetsBinding.instance
.addPostFrameCallback((_) => setState(() {}));
这样,您可以确定在构建当前小部件后它会被执行。
答案 3 :(得分:1)
使用Timer
类,
import 'dart:async';
@override
void initState() {
super.initState();
Timer.run(() {
// You can call setState from here
});
}
答案 4 :(得分:0)
由于提供的答案似乎是正确的,因此我做了个变通,因为无法从构建中简单地将其删除。
我使用Future.delayed(Duration.zero, () => setState(() { ... }));
代替setState,对于可能也使用setState的方法也是如此。
编辑:source
答案 5 :(得分:0)
在制作需要执行Navigator.pop
的小部件之前,我在返回build
中的小部件时遇到了同样的问题。
让我叫Rémi Rousselet中的代码:
Widget build(BuildContext context) {
Navigator.pop(context);
return Container();
}
上面的代码将导致错误,但是您只能弹出context
在build
中的原因,所以怎么办?
Widget build(BuildContext context) {
if(datas != null) // check datas
{
SchedulerBinding.instance.addPostFrameCallback((_){ // make pop action to next cycle
Navigator.of(context).pop(datas); /*...your datas*/
});
}
return Container();
}
此方法是其他方法的组合,但我不确定这是否是最佳做法,如果有任何错误,请发表评论以指出我的意思!
答案 6 :(得分:0)
我在每次打开或重新加载时在 LoginScreen 控制用户。如果用户通过身份验证,我导航到家。在这一点上我得到同样的错误。据我了解,这是关于导航器自己的 setState 。 addPostFrameCallback 或计时器修复它。
void initState() {
super.initState();
if (auth.getUser != null) {
// ERROR
// Navigator.pushReplacementNamed(context, '/home');
// SUCCESS
// WidgetsBinding.instance.addPostFrameCallback((_) => setState(() {
// Navigator.pushReplacementNamed(context, '/home');
// }));
// SUCCESS
Timer.run(() {
Navigator.pushReplacementNamed(context, '/home');
});
}
}
答案 7 :(得分:-1)
Mongo
方法内的@Injectable()
和success: function (response)
{
document.getElementById("recovery").innerHTML = response.data.recovery;
$("#updatemodal").modal();
}
上的setState
使用了两个选项
将setState包装在其中一个
中 build
或context
或initState
或WidgetsBinding.instance.addPostFrameCallback
示例:
Future.microTask()