Flutter 页面改写机制
StateFullWidget页面改写
updateChild
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;
if (hasSameSuperclass && child.widget == newWidget) {
if (child.slot != newSlot) {
updateSlotForChild(child, newSlot);
}
newChild = child;
} else if (hasSameSuperclass && Widget.canUpdate(child.widget, newWidget)) {
if (child.slot != newSlot) {
updateSlotForChild(child, newSlot);
}
child.update(newWidget);
newChild = child;
} else {
deactivateChild(child);
newChild = inflateWidget(newWidget, newSlot);
}
} else {
newChild = inflateWidget(newWidget, newSlot);
}
final Key? key = newWidget.key;
if (key is GlobalKey) {
owner!._debugReserveGlobalKeyFor(this, newChild, key);
}
return newChild;
}
这段Flutter源码是关于Element类中的updateChild办法。Element是Flutter结构中用于构建和办理Widget树的基本元素:
以下是对该办法履行流程的扼要分析:
参数检查: 办法接受三个参数,child表明当时的子元素(能够为null),newWidget表明新的Widget,newSlot表明新的槽(slot)。
处理newWidget为null的状况: 假如newWidget为null,表明要移除当时的子元素,因此会调用deactivateChild(child)来停用当时的子元素,并回来null。
处理newWidget不为null的状况:
-
a. 假如当时child不为null,表明存在已有的子元素。
-
b. 检查是否具有相同的父类(hasSameSuperclass),假如有,则进行进一步的比较。
-
c. 假如child.widget与newWidget相同,且child.slot与newSlot不同,则更新child的槽。
-
d. 假如child.widget与newWidget相同且槽相同,直接回来child。
-
e. 假如具有相同的父类且Widget.canUpdate(child.widget, newWidget)为true,则表明能够直接更新child的Widget。更新槽并回来child。
canUpdate 办法实现为:
static bool canUpdate(Widget oldWidget, Widget newWidget) {
return oldWidget.runtimeType == newWidget.runtimeType
&& oldWidget.key == newWidget.key;
}
-
f. 假如以上条件都不满足,调用deactivateChild(child)来停用当时子元素。
-
g. 调用 inflateWidget(newWidget, newSlot)来创立并回来新的子元素。
处理child为null的状况: 假如child为null,表明当时没有子元素,直接调用inflateWidget(newWidget, newSlot)来创立并回来新的子元素。
回来结果: 回来新创立的子元素newChild。
这段代码首要负责办理Element的子元素,依据新的Widget和槽来更新或创立子元素,并依据必定的条件判别是否需求停用当时子元素。
继续查看inflateWidget 函数:
Element inflateWidget(Widget newWidget, Object? newSlot) {
try {
final Key? key = newWidget.key;
if (key is GlobalKey) {
final Element? newChild = _retakeInactiveElement(key, newWidget);
if (newChild != null) {
newChild._activateWithParent(this, newSlot);
final Element? updatedChild = updateChild(newChild, newWidget, newSlot);
return updatedChild!;
}
}
final Element newChild = newWidget.createElement();
newChild.mount(this, newSlot);
return newChild;
} finally {
}
}
在看createElement办法
abstract class StatefulWidget extends Widget {
const StatefulWidget({ super.key });
@override
StatefulElement createElement() => StatefulElement(this);
}
在看下StatefulElement办法:
class StatefulElement extends ComponentElement {
StatefulElement(StatefulWidget widget)
: _state = widget.createState(),
super(widget) {
state._element = this;
state._widget = widget;
}
}
回到inflateWidget办法
Element inflateWidget(Widget newWidget, Object? newSlot) {
try {
final Key? key = newWidget.key;
if (key is GlobalKey) {
final Element? newChild = _retakeInactiveElement(key, newWidget);
if (newChild != null) {
newChild._activateWithParent(this, newSlot);
final Element? updatedChild = updateChild(newChild, newWidget, newSlot);
return updatedChild!;
}
}
final Element newChild = newWidget.createElement();
newChild.mount(this, newSlot);
return newChild;
} finally {
}
}
看一下 newChild.mount(this, newSlot); 的履行:
abstract class ComponentElement extends Element {
void mount(Element? parent, Object? newSlot) {
_firstBuild();
}
}
在看下 _firstBuild办法:
class StatefulElement extends ComponentElement {
void _firstBuild() {
try {
final Object? debugCheckForReturnedFuture = state.initState() as dynamic;
} finally {
}
state.didChangeDependencies();
super._firstBuild();
}
}
}
在这里调用了 state.initState()
StateFullWidget inflateWidget 总结
所以widget改写中, 在inflateWidget中创立新的element ,全体的履行次序如下:
- createElement
- createState
- initState
- didChangeDependencies
- build
hasSameSuperClass didUpdateWidget改写
假如statefullwidget key没变,则调用次序如下:
回到流程:
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;
if (hasSameSuperclass && child.widget == newWidget) {
if (child.slot != newSlot) {
updateSlotForChild(child, newSlot);
}
newChild = child;
} else if (hasSameSuperclass && Widget.canUpdate(child.widget, newWidget)) {
if (child.slot != newSlot) {
updateSlotForChild(child, newSlot);
}
child.update(newWidget);
newChild = child;
} else {
deactivateChild(child);
newChild = inflateWidget(newWidget, newSlot);
}
} else {
newChild = inflateWidget(newWidget, newSlot);
}
final Key? key = newWidget.key;
if (key is GlobalKey) {
owner!._debugReserveGlobalKeyFor(this, newChild, key);
}
return newChild;
}
看下 child.update(newWidget);
class StatefulElement extends ComponentElement {
void update(StatefulWidget newWidget) {
super.update(newWidget);
assert(widget == newWidget);
final StatefulWidget oldWidget = state._widget!;
_dirty = true;
state._widget = widget as StatefulWidget;
try {
_debugSetAllowIgnoredCallsToMarkNeedsBuild(true);
final Object? debugCheckForReturnedFuture = state.didUpdateWidget(oldWidget) as dynamic;
} finally {
_debugSetAllowIgnoredCallsToMarkNeedsBuild(false);
}
rebuild();
}
}
在这一步调用的state.didUpdateWidget(oldWidget)
rebuild();办法如下
Element rebuild
abstract class Element extends DiagnosticableTree implements BuildContext {
void rebuild() {
performRebuild();
}
}
ComponentElement performRebuild
abstract class ComponentElement extends Element {
void performRebuild() {
Widget? built;
try {
built = build();
}
try {
_child = updateChild(_child, built, slot);
} catch (e, stack) {
_child = updateChild(null, built, slot);
}
}
}
StatefulElement build
class StatefulElement extends ComponentElement {
Widget build() => state.build(this);
}
假如statefullwidget didUpdateWidget总结
假如statefullwidget key没变,则调用次序如下:
- didUpdateWidget
- build
总结
-
StatefulWidget:
-
StatefulWidget
是一个有状况的Widget,它能够包含随时间变化的数据(状况)。 - 通过调用
setState
办法,能够告诉Flutter结构需求从头构建UI,以便更新状况。
-
-
State:
-
StatefulWidget
的状况被封装在对应的State
目标中。 -
State
目标包含与UI交互的逻辑,而且能够在initState
、didUpdateWidget
等生命周期办法中进行恰当的处理。
-
-
hasSameSuperclass:
- 在你flutter的源代码中,有一个
hasSameSuperclass
的变量,这用于检查两个Widget是否有相同的父类。 - 假如两个Widget具有相同的父类,可能会影响到是否能够直接复用现有的
Element
目标。
- 在你flutter的源代码中,有一个
-
Key:
- 在Flutter中,
Key
是用于标识Widget的目标,能够协助Flutter结构更好地办理Widget树的更新。 - 假如两个Widget具有相同的
Key
,Flutter可能会以为它们表明相同的逻辑实体,并测验进行更新而不是毁掉和重建。
- 在Flutter中,
在StatefulWidget
更新时,结构会测验智能地更新现有的Element
目标,而不是毁掉并从头构建整个Widget树。关键因素包括:
-
Key的使用: 假如Widget具有
Key
,结构会测验匹配新旧Widget的Key,以确定是否能够复用现有的Element
目标。 -
State的生命周期办法:
State
目标的生命周期办法,如initState
和didUpdateWidget
,能够用于履行恰当的逻辑,以呼应Widget的更新。 -
相同Widget类型的比较: 在你供给的代码中,有一段比较
child.widget == newWidget
的逻辑,这可能涉及到判别是否是相同类型的Widget。
-
hasSameSuperclass严重效果
-
假如statefullwidget key没变,则调用次序如下:
- didUpdateWidget
- build
-
runtimetype相同可是key产生修正,在inflateWidget中创立新的element ,全体的履行次序如下:
- createElement
- createState
- initState
- didChangeDependencies
- build
-