When calling setState(), you must not have called the dispose() method. Otherwise, an error occurs. You can judge whether calling this method is legal through the mounted attribute.
if (mounted) { setState(() {}); }
See clearly in the framework In addition to some conditions, the setstate method in dart can be judged as follows:
_element.markNeedsBuild();
Let's take a look at markNeedsBuild.
Class needmark needelement
void markNeedsBuild() { assert(_debugLifecycleState != _ElementLifecycle.defunct); if (!_active) return;//return ... if (dirty) return; _dirty = true; //Call the scheduleBuildFor method owner.scheduleBuildFor(this); }
Mark the element as "dirty" and add it to the global "dirty" linked list so that it can be updated when the signal is updated in the next frame
-
The "dirty" linked list here is the linked list to be updated. After the update, it will not be "dirty".
-
Because it's a little inefficient to update twice a frame, so_ Return directly when active=false.
Let's take a look at the scheduleBuildFor method that the method finally calls.
BuildOwner class scheduleBuildFor method
The BuildOwner class is the management class of the widget framework, which tracks those widgets that need to be rebuilt.
void scheduleBuildFor(Element element) { ... if (element._inDirtyList) { ... _dirtyElementsNeedsResorting = true; return; } if (!_scheduledFlushDirtyElements && onBuildScheduled != null) { _scheduledFlushDirtyElements = true; onBuildScheduled();//Callback } _dirtyElements.add(element);//Add element to the dirty element list element._inDirtyList = true; assert(() { if (debugPrintScheduleBuildForStacks) debugPrint('...dirty list is now: $_dirtyElements'); return true; }()); }
Add an element to_ dirtyElements linked list for widgetsbinding DrawFrame can reconstruct element when calling buildScope. onBuildScheduled() is a callback of BuildOwner.
The callback of the instancescheonscheduled is initialized in the instancescheonschedules.
mixin WidgetsBinding on BindingBase, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding { @override void initInstances() { super.initInstances(); _instance = this; // here buildOwner.onBuildScheduled = _handleBuildScheduled; window.onLocaleChanged = handleLocaleChanged;window.onAccessibilityFeaturesChanged = handleAccessibilityFeaturesChanged; SystemChannels.navigation.setMethodCallHandler(_handleNavigationInvocation); SystemChannels.system.setMessageHandler(_handleSystemMessage); FlutterErrorDetails.propertiesTransformers.add(transformDebugCreator); } }
We can see buildowner The onbuildscheduled callback is equal to_ handleBuildScheduled, let's take a look at this now_ handleBuildScheduled method:
void _handleBuildScheduled() { //Call ensurevisuanupdate ensureVisualUpdate(); }
You can see that the ensurevisuanupdate method is called, so let's go on.
SchedulerBinding class ensurevisuanupdate method
void ensureVisualUpdate() { switch (schedulerPhase) { case SchedulerPhase.idle: case SchedulerPhase.postFrameCallbacks: //When schedulerPhase is schedulerPhase idle, //SchedulerPhase. Called when postframecallbacks //scheduleFrame() scheduleFrame(); return; case SchedulerPhase.transientCallbacks: case SchedulerPhase.midFrameMicrotasks: case SchedulerPhase.persistentCallbacks: return; } }
The five enumeration values of SchedulerPhase are respectively:
state | meaning |
---|---|
idle | There is no frame being processed. It may be widgetsbinding Scheduletask, scheduleMicrotask, Timer, event handlers, or other callbacks |
transientCallbacks | SchedulerBinding. The handlebeginframe procedure handles animation status updates |
midFrameMicrotasks | Process Microtasks triggered by the transient callbacks phase |
persistentCallbacks | WidgetsBinding.drawFrame and schedulerbinding Handledrawframe process, build/layout/paint pipeline work |
postFrameCallbacks | It is mainly to clean up and plan to execute the work of the next frame |
The second case calls the scheduleFrame() method
Let's look at the scheduleFrame() method
void scheduleFrame() { if (_hasScheduledFrame || !_framesEnabled) return; assert(() { if (debugPrintScheduleFrameStacks) debugPrintStack( label: 'scheduleFrame() called. Current phase is $schedulerPhase.'); return true; }()); //Calling the scheduleFrame method of Window is a native method window.scheduleFrame(); _hasScheduledFrame = true; }
WidgetsFlutterBinding is mixed with these bindings, which basically listen to and process some events of Window objects, and then wrap, abstract and distribute these events according to the model of the Framework. You can see that WidgetsFlutterBinding is the "glue" between the Flutter engine and the upper Framework.
name | explain |
---|---|
GestureBinding | Provides window The onpointerdatapacket callback is bound to the Framework gesture subsystem and is the binding entry between the Framework event model and the underlying events |
ServicesBinding | Provides window Onplatformmessage callback, which is used to bind the platform message channel and mainly handles native and fluent communication |
SchedulerBinding | Provides window Onbeginframe and window Ondrawframe callback, listen to refresh events, bind Framework drawing and scheduling subsystem |
PaintingBinding | Binding drawing library, which is mainly used to process picture caching |
SemanticsBinding | The bridge between semantic layer and fluent engine is mainly the bottom support of auxiliary functions |
RendererBinding | Provides window onMetricsChanged ,window.onTextScaleFactorChanged and other callbacks. It is the bridge between rendering tree and fluent engine |
WidgetsBinding | Provides window Onlocalechanged, onBuildScheduled and other callbacks. It is the bridge between the fluent widget layer and engine |
As mentioned in the previous article, the rendering logic of UI is implemented in the Render tree, so let's take a closer look at the logic of renderebinding.
RendererBinding
void initInstances() { ... //Listen for events of Window object ui.window ..onMetricsChanged = handleMetricsChanged ..onTextScaleFactorChanged = handleTextScaleFactorChanged ..onSemanticsEnabledChanged = _handleSemanticsEnabledChanged ..onSemanticsAction = _handleSemanticsAction; //Add PersistentFrameCallback addPersistentFrameCallback(_handlePersistentFrameCallback); }
addPersistentFrameCallback_ Handlepersistent framecallback finally calls drawFrame, and WidgetsBinding overrides the drawFrame() method in RendererBinding. Finally, we found that we returned to the WidgetsBinding class. The implementation of drawFrame in WidgetsBinding is as follows:
@override void drawFrame() { ... try { if (renderViewElement != null) // Refactoring element s that need to be updated buildOwner.buildScope(renderViewElement); super.drawFrame(); //Call the drawFrame() method of RendererBinding buildOwner.finalizeTree(); } }
In the above scheduleBuildFor method introduction, it is mentioned: "scheduleBuildFor adds a element to the _dirtyElements list, so that element can be reconstructed when buildScope is invoked in [WidgetsBinding.drawFrame]. onBuildScheduled() is a BuildOwner callback". Calling buildOwner. in drawFrame Buildscope (renderviveelement) updates elements.
void buildScope(Element context, [ VoidCallback callback ]) { ... while (index < dirtyCount) { assert(_dirtyElements[index] != null); assert(_dirtyElements[index]._inDirtyList); assert(!_dirtyElements[index]._active || _dirtyElements[index]._debugIsInScope(context)); try { //while loop for element refactoring _dirtyElements[index].rebuild(); } catch (e, stack) { ... } } }
obtain
Conditional judgment
-
1. Life cycle judgment
-
2. Is mounted installed
Management class
-
1. Tell the management method that it needs to be rebuilt
-
That is, the buildouwner class scheduleBuildFor method
Add dirty linked list
-
"Dirty" linked list is a linked list to be updated
-
2. After the update, it will not be "dirty"
-
3._ Return directly when active = false
Call window scheduleFrame()
-
native method
-
Package, abstract and distribute according to the model of the Framework
-
WidgetsFlutterBinding is the "glue" between the Flutter engine and the upper Framework
-
The drawing logic of UI is implemented in the Render tree
Update the frame signal to refresh the interface to be reconstructed
-
"scheduleBuildFor is to add an element to the _dirtyelementslinked list
-
It is easy to reconstruct element when calling buildScope in [WidgetsBinding.drawFrame].
-
onBuildScheduled() is a callback of BuildOwner“
-
Calling buildOwner. in drawFrame Buildscope (renderviveelement) update elements