I am having trouble finding the source to this exception, and the app is quite complex so it is hard to show any relevant part of the code. This is my repository at the point where the error happens: Github repo
I suspect the following code might be the perpetrator:
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) ], ), ), ], ), ); }
The error appears when showing a dialog, and when the user presses a button on the dialog, two Redux store dispatches are sent directly after each other. The UI behind the dialog subscribes to changes in the Redux store.
I thought Dart/Flutter was single-threaded so no collision like this could happen, where it seems like a thread is calling setState() on a widget while another has put a lock on the widget tree.
Is there a way of checking if the widget tree is locked so this can be avoided?
The stack provides this info:
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): ════════════════════════════════════════════════════════════════════════════════════════════════════
Special case of using Scaffold
and Drawer
:
That fail can also happen if you try to rebuild the tree with opened Drawer
. For example if you send a message to a Bloc
that forces rebuilding of the whole page/screen.
Consider to call Navigator.pop(context)
first in your tap handler.
As a workaround wrap your code that calling setState
into WidgetsBinding.addPostFrameCallback:
WidgetsBinding.instance .addPostFrameCallback((_) => setState(() {}));
That way you can be sure it gets executed after the current widget is built.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With