SetState方法
_element!.markNeedsBuild();
除去一些判断外 最终是调用了_element!.markNeedsBuild();
if (_lifecycleState != _ElementLifecycle.active) {
return;
}
if (dirty) {
return;
}
_dirty = true;
owner!.scheduleBuildFor(this);
防止重复刷新 这里判断了 _lifecycleState != _ElementLifecycle.active 该值在mount方法中设置为active,owner也是在mount中赋值的
同时若是当亲已被标记dirty,也不刷新
接下来是owner!.scheduleBuildFor(this)
if (!_scheduledFlushDirtyElements && onBuildScheduled != null) {
_scheduledFlushDirtyElements = true;
onBuildScheduled!();
}
_dirtyElements.add(element);
element._inDirtyList = true;
这里调用onBuildScheduled进行回调状态
同时将element加入dirty列表,并做标记
onBuildScheduled!();
mixin WidgetsBinding on BindingBase, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding {
@override
void initInstances() {
super.initInstances();
_instance = this;
// 这里
buildOwner.onBuildScheduled = _handleBuildScheduled;
window.onLocaleChanged = handleLocaleChanged;window.onAccessibilityFeaturesChanged = handleAccessibilityFeaturesChanged;
SystemChannels.navigation.setMethodCallHandler(_handleNavigationInvocation);
SystemChannels.system.setMessageHandler(_handleSystemMessage); FlutterErrorDetails.propertiesTransformers.add(transformDebugCreator);
}
}
可以看出,在WidgetsBinding初始化的时候就进行了绑定,最终调用的是_handleBuildScheduled
void _handleBuildScheduled() {
//调用ensureVisualUpdate
ensureVisualUpdate();
}
ensureVisualUpdate()
void ensureVisualUpdate() {
switch (schedulerPhase) {
case SchedulerPhase.idle:
case SchedulerPhase.postFrameCallbacks:
scheduleFrame();
return;
case SchedulerPhase.transientCallbacks:
case SchedulerPhase.midFrameMicrotasks:
case SchedulerPhase.persistentCallbacks:
return;
}
}
SchedulerPhase.postFrameCallbacks
这里我们主要看 postFrameCallbacks 执行下一帧的渲染工作
scheduleFrame() {
//调用Window 的scheduleFrame方法是一个 native 方法
window.scheduleFrame();
}
WidgetsBinding 混入的这些 Binding 中基本都是监听并处理 Window 对象的一些事件,然后将这些事件按照 Framework 的模型包装、抽象然后分发。可以看到 WidgetsBinding 正是粘连 Flutter engine 与上层 Framework 的“胶水”。
window.scheduleFrame
/// 注册回调
ensureFrameCallbacksRegistered();
/// 向引擎发送消息
platformDispatcher.scheduleFrame();
接着是绘制回调
@override
void drawFrame() {
...
try {
if (renderViewElement != null)
// 重构需要更新的element
buildOwner.buildScope(renderViewElement);
super.drawFrame(); //调用RendererBinding的drawFrame()方法
buildOwner.finalizeTree();
}
}
buildOwner.buildScope(renderViewElement);
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 循环进行元素重构
_dirtyElements[index].rebuild();
} catch (e, stack) {
...
}
}
for (final Element element in _dirtyElements) {
assert(element._inDirtyList);
element._inDirtyList = false;
}
_dirtyElements.clear();
_scheduledFlushDirtyElements = false;
_dirtyElementsNeedsResorting = null;
if (!kReleaseMode) {
FlutterTimeline.finishSync();
}
}
_dirtyElements[index].rebuild() 元素重构,重构后 将dirtyelement _inDirtyList = false 将dirtyelement数组清空
performRebuild() {
_dirty = false;
if (_newWidget != null) {
// _newWidget can be null if, for instance, we were rebuilt
// due to a reassemble.
final Widget newWidget = _newWidget!;
_newWidget = null;
update(newWidget as RenderObjectToWidgetAdapter<T>);
}
}
performRebuild 将_dirty置为false
update(newWidget as RenderObjectToWidgetAdapter<T>); 更新widget
void _rebuild() {
try {
_child = updateChild(_child, (widget as RenderObjectToWidgetAdapter<T>).child, _rootChildSlot);
} catch (exception, stack) {
final FlutterErrorDetails details = FlutterErrorDetails(
exception: exception,
stack: stack,
library: 'widgets library',
context: ErrorDescription('attaching to the render tree'),
);
FlutterError.reportError(details);
final Widget error = ErrorWidget.builder(details);
_child = updateChild(null, error, _rootChildSlot);
}
}
更新child
Element? updateChild(Element? child, Widget? newWidget, Object? newSlot) {
if (newWidget == null) {
if (child != null) {
deactivateChild(child);
}
return null;
}
final Element newChild;
if (child != null) {
bool hasSameSuperclass = true;
// When the type of a widget is changed between Stateful and Stateless via
// hot reload, the element tree will end up in a partially invalid state.
// That is, if the widget was a StatefulWidget and is now a StatelessWidget,
// then the element tree currently contains a StatefulElement that is incorrectly
// referencing a StatelessWidget (and likewise with StatelessElement).
//
// To avoid crashing due to type errors, we need to gently guide the invalid
// element out of the tree. To do so, we ensure that the `hasSameSuperclass` condition
// returns false which prevents us from trying to update the existing element
// incorrectly.
//
// For the case where the widget becomes Stateful, we also need to avoid
// accessing `StatelessElement.widget` as the cast on the getter will
// cause a type error to be thrown. Here we avoid that by short-circuiting
// the `Widget.canUpdate` check once `hasSameSuperclass` is false.
assert(() {
final int oldElementClass = Element._debugConcreteSubtype(child);
final int newWidgetClass = Widget._debugConcreteSubtype(newWidget);
hasSameSuperclass = oldElementClass == newWidgetClass;
return true;
}());
if (hasSameSuperclass && child.widget == newWidget) {
// We don't insert a timeline event here, because otherwise it's
// confusing that widgets that "don't update" (because they didn't
// change) get "charged" on the timeline.
if (child.slot != newSlot) {
updateSlotForChild(child, newSlot);
}
newChild = child;
} else if (hasSameSuperclass && Widget.canUpdate(child.widget, newWidget)) {
if (child.slot != newSlot) {
updateSlotForChild(child, newSlot);
}
final bool isTimelineTracked = !kReleaseMode && _isProfileBuildsEnabledFor(newWidget);
if (isTimelineTracked) {
Map<String, String>? debugTimelineArguments;
assert(() {
if (kDebugMode && debugEnhanceBuildTimelineArguments) {
debugTimelineArguments = newWidget.toDiagnosticsNode().toTimelineArguments();
}
return true;
}());
FlutterTimeline.startSync(
'${newWidget.runtimeType}',
arguments: debugTimelineArguments,
);
}
child.update(newWidget);
if (isTimelineTracked) {
FlutterTimeline.finishSync();
}
assert(child.widget == newWidget);
assert(() {
child.owner!._debugElementWasRebuilt(child);
return true;
}());
newChild = child;
} else {
deactivateChild(child);
assert(child._parent == null);
// The [debugProfileBuildsEnabled] code for this branch is inside
// [inflateWidget], since some [Element]s call [inflateWidget] directly
// instead of going through [updateChild].
newChild = inflateWidget(newWidget, newSlot);
}
} else {
// The [debugProfileBuildsEnabled] code for this branch is inside
// [inflateWidget], since some [Element]s call [inflateWidget] directly
// instead of going through [updateChild].
newChild = inflateWidget(newWidget, newSlot);
}
assert(() {
if (child != null) {
_debugRemoveGlobalKeyReservation(child);
}
final Key? key = newWidget.key;
if (key is GlobalKey) {
assert(owner != null);
owner!._debugReserveGlobalKeyFor(this, newChild, key);
}
return true;
}());
return newChild;
}
- 新旧widget有同样的父类且widget相同,则只更新slot(由parent设置,用于确定位于parent中的位置)
- 父类相同,且Widget.canUpdate返回true,则更新element对应的widget配置
- 否则,将原element置为deactate,使用inflateWidget创建新的element
inflateWidget 中执行element的mount方法,更新全局的globalKey,更新依赖,更新notification,同时执行rebuild
至此更新完毕
常用容器widget的生命周期
- StatelessWidget生命周期
build 每次界面刷新的时候都会调用 - StatefulWidget生命周期
createState - 创建的时候调用 且只调用一次
initState - 创建后调用的第一个方法 类似iOS的viewdidload,此时mount变为true,直到disponse才变为false
didChangeDependencies - 第一次创建的时候 会在initstate后立即调用,当刷新的时候就不调用了,除非widget依赖的 ingeritrWidget发生变化,所以 didChangeDependencies 可能会多次调用
build - 创建后会在调用didChangeDependencies 后立即调用
重新渲染时,也会调用
addPostFrameCallback - 添加当前帧的绘制回调,只调用一次,我们一般会在initstate中添加当前帧的回调
import 'package:flutter/scheduler.dart';
@override
void initState() {super.initState();SchedulerBinding.instance.addPostFrameCallback((_) => {});
}
addPersistentFrameCallback - 实时frame绘制回调,这个函数会在每次绘制frame结束后调用,可以用作FPS的检测
didUpdateWidget - 是否复用widget时才会调用
deactivate - 当前widgetkey或是类型发生变化,需要重新创建element,将原state从移除调用
dispose - widget不需要再显示,从渲染树中移除,state永久移除,会调用该方法,可以在该方法中取消监听,动画的操作