Flutter开发进阶之瞧瞧Widget
在Flutter开发中,WIdget是构建界面的基本单元;Widget是不可变的,意味着一旦创建如果需要改变UI就需要重新创建一个新的Widget;在实际开发中,Widget通常由一个个Widget组合而成,从而形成嵌套的树形结构,复杂的UI就是由这一个个Widget构建而成;Widget分为有状态和无状态,无状态Stateless根据输入参数渲染UI,有状态Stateful可以管理自己的状态并重建UI。
这篇文章将通过解析Widget的构成去理解Widget。
Widget
abstract class Widget extends DiagnosticableTree {
const Widget({ this.key });
final Key? key;
Element createElement();
String toStringShort() {
final String type = objectRuntimeType(this, 'Widget');
return key == null ? type : '$type-$key';
}
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense;
}
bool operator ==(Object other) => super == other;
int get hashCode => super.hashCode;
static bool canUpdate(Widget oldWidget, Widget newWidget) {
return oldWidget.runtimeType == newWidget.runtimeType
&& oldWidget.key == newWidget.key;
}
static int _debugConcreteSubtype(Widget widget) {
return widget is StatefulWidget ? 1 :
widget is StatelessWidget ? 2 :
0;
}
}
以上是系统源码,可以看到Widget本身是@immutable,意思是不可变的,这与我们的猜想一致。
Widget继承自DiagnosticableTree说明Widget允许以树形组织呈现诊断信息,DiagnosticableTree混合了Diagnosticable的抽象类,它是Flutter框架用于调试和诊断的工具之一,通过DiagnosticableTree可以方便查看和理解应用内部状态以及问题的根源。
Widget默认带有属性key,通过查看Key的源码,以下。
abstract class Key {
const factory Key(String value) = ValueKey<String>;
const Key.empty();
}
同上,Key也是不可变的,默认的Key为ValueKey ,通过查看ValueKey的源码,以下。
class ValueKey<T> extends LocalKey {
const ValueKey(this.value);
final T value;
bool operator ==(Object other) {
if (other.runtimeType != runtimeType) {
return false;
}
return other is ValueKey<T>
&& other.value == value;
}
int get hashCode => Object.hash(runtimeType, value);
String toString() {
final String valueString = T == String ? "<'$value'>" : '<$value>';
if (runtimeType == _TypeLiteral<ValueKey<T>>().type) {
return '[$valueString]';
}
return '[$T $valueString]';
}
}
ValueKey继承自LocalKey,继续查看LocalKey,以下。
abstract class LocalKey extends Key {
const LocalKey() : super.empty();
}
发现LocalKey继承自Key,完成闭环。
继续向下解析,每个Widget会对应一个Element,这是基本单元对应的实例,通过createElement创建,通过查看源码abstract class Element extends DiagnosticableTree implements BuildContext
可知Element即为BuildContext。
继续向下解析,Widget的刷新机制通过比较新旧Widget的runtimeType和key去作为标准。
继续解析Widget就不得不查看Element,代码实在有些长,就不贴了。
StatelessWidget
abstract class StatelessWidget extends Widget {
const StatelessWidget({ super.key });
StatelessElement createElement() => StatelessElement(this);
Widget build(BuildContext context);
}
StatelessWidget继承自Widget,createElement会将Widget作为参数传递给StatelessElement的初始化方法,通过查看StatelessElement源码,以下。
class StatelessElement extends ComponentElement {
StatelessElement(StatelessWidget super.widget);
Widget build() => (widget as StatelessWidget).build(this);
void update(StatelessWidget newWidget) {
super.update(newWidget);
assert(widget == newWidget);
rebuild(force: true);
}
}
联系起来,createElement会将Widget交给Element,Element的update会调用Widget的canUpdate,最终会判断调用build,build会将Element自身作为BuildContext交给StatelessWidget。
StatefulWidget
abstract class StatefulWidget extends Widget {
const StatefulWidget({ super.key });
StatefulElement createElement() => StatefulElement(this);
State createState();
}
StatefulWidget相对而言多一个State<StatefulWidget>? _state
,在StatefulElement的初始化方法中,以下。
StatefulElement(StatefulWidget widget)
: _state = widget.createState(),
super(widget) {
assert(() {
if (!state._debugTypesAreRight(widget)) {
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('StatefulWidget.createState must return a subtype of State<${widget.runtimeType}>'),
ErrorDescription(
'The createState function for ${widget.runtimeType} returned a state '
'of type ${state.runtimeType}, which is not a subtype of '
'State<${widget.runtimeType}>, violating the contract for createState.',
),
]);
}
return true;
}());
assert(state._element == null);
state._element = this;
assert(
state._widget == null,
'The createState function for $widget returned an old or invalid state '
'instance: ${state._widget}, which is not null, violating the contract '
'for createState.',
);
state._widget = widget;
assert(state._debugLifecycleState == _StateLifecycle.created);
}
会调用Widget的createState方法。
继续查看StatefulElement源码,以下。
class StatefulElement extends ComponentElement {
/// Creates an element that uses the given widget as its configuration.
StatefulElement(StatefulWidget widget)
: _state = widget.createState(),
super(widget) {
assert(() {
if (!state._debugTypesAreRight(widget)) {
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('StatefulWidget.createState must return a subtype of State<${widget.runtimeType}>'),
ErrorDescription(
'The createState function for ${widget.runtimeType} returned a state '
'of type ${state.runtimeType}, which is not a subtype of '
'State<${widget.runtimeType}>, violating the contract for createState.',
),
]);
}
return true;
}());
assert(state._element == null);
state._element = this;
assert(
state._widget == null,
'The createState function for $widget returned an old or invalid state '
'instance: ${state._widget}, which is not null, violating the contract '
'for createState.',
);
state._widget = widget;
assert(state._debugLifecycleState == _StateLifecycle.created);
}
Widget build() => state.build(this);
State<StatefulWidget> get state => _state!;
State<StatefulWidget>? _state;
void reassemble() {
if (_debugShouldReassemble(_debugReassembleConfig, _widget)) {
state.reassemble();
}
super.reassemble();
}
void _firstBuild() {
assert(state._debugLifecycleState == _StateLifecycle.created);
final Object? debugCheckForReturnedFuture = state.initState() as dynamic;
assert(() {
if (debugCheckForReturnedFuture is Future) {
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('${state.runtimeType}.initState() returned a Future.'),
ErrorDescription('State.initState() must be a void method without an `async` keyword.'),
ErrorHint(
'Rather than awaiting on asynchronous work directly inside of initState, '
'call a separate method to do this work without awaiting it.',
),
]);
}
return true;
}());
assert(() {
state._debugLifecycleState = _StateLifecycle.initialized;
return true;
}());
state.didChangeDependencies();
assert(() {
state._debugLifecycleState = _StateLifecycle.ready;
return true;
}());
super._firstBuild();
}
void performRebuild() {
if (_didChangeDependencies) {
state.didChangeDependencies();
_didChangeDependencies = false;
}
super.performRebuild();
}
void update(StatefulWidget newWidget) {
super.update(newWidget);
assert(widget == newWidget);
final StatefulWidget oldWidget = state._widget!;
state._widget = widget as StatefulWidget;
final Object? debugCheckForReturnedFuture = state.didUpdateWidget(oldWidget) as dynamic;
assert(() {
if (debugCheckForReturnedFuture is Future) {
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('${state.runtimeType}.didUpdateWidget() returned a Future.'),
ErrorDescription( 'State.didUpdateWidget() must be a void method without an `async` keyword.'),
ErrorHint(
'Rather than awaiting on asynchronous work directly inside of didUpdateWidget, '
'call a separate method to do this work without awaiting it.',
),
]);
}
return true;
}());
rebuild(force: true);
}
void activate() {
super.activate();
state.activate();
assert(_lifecycleState == _ElementLifecycle.active);
markNeedsBuild();
}
void deactivate() {
state.deactivate();
super.deactivate();
}
void unmount() {
super.unmount();
state.dispose();
assert(() {
if (state._debugLifecycleState == _StateLifecycle.defunct) {
return true;
}
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('${state.runtimeType}.dispose failed to call super.dispose.'),
ErrorDescription(
'dispose() implementations must always call their superclass dispose() method, to ensure '
'that all the resources used by the widget are fully released.',
),
]);
}());
state._element = null;
_state = null;
}
InheritedWidget dependOnInheritedElement(Element ancestor, { Object? aspect }) {
assert(() {
final Type targetType = ancestor.widget.runtimeType;
if (state._debugLifecycleState == _StateLifecycle.created) {
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('dependOnInheritedWidgetOfExactType<$targetType>() or dependOnInheritedElement() was called before ${state.runtimeType}.initState() completed.'),
ErrorDescription(
'When an inherited widget changes, for example if the value of Theme.of() changes, '
"its dependent widgets are rebuilt. If the dependent widget's reference to "
'the inherited widget is in a constructor or an initState() method, '
'then the rebuilt dependent widget will not reflect the changes in the '
'inherited widget.',
),
ErrorHint(
'Typically references to inherited widgets should occur in widget build() methods. Alternatively, '
'initialization based on inherited widgets can be placed in the didChangeDependencies method, which '
'is called after initState and whenever the dependencies change thereafter.',
),
]);
}
if (state._debugLifecycleState == _StateLifecycle.defunct) {
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('dependOnInheritedWidgetOfExactType<$targetType>() or dependOnInheritedElement() was called after dispose(): $this'),
ErrorDescription(
'This error happens if you call dependOnInheritedWidgetOfExactType() on the '
'BuildContext for a widget that no longer appears in the widget tree '
'(e.g., whose parent widget no longer includes the widget in its '
'build). This error can occur when code calls '
'dependOnInheritedWidgetOfExactType() from a timer or an animation callback.',
),
ErrorHint(
'The preferred solution is to cancel the timer or stop listening to the '
'animation in the dispose() callback. Another solution is to check the '
'"mounted" property of this object before calling '
'dependOnInheritedWidgetOfExactType() to ensure the object is still in the '
'tree.',
),
ErrorHint(
'This error might indicate a memory leak if '
'dependOnInheritedWidgetOfExactType() is being called because another object '
'is retaining a reference to this State object after it has been '
'removed from the tree. To avoid memory leaks, consider breaking the '
'reference to this object during dispose().',
),
]);
}
return true;
}());
return super.dependOnInheritedElement(ancestor as InheritedElement, aspect: aspect);
}
bool _didChangeDependencies = false;
void didChangeDependencies() {
super.didChangeDependencies();
_didChangeDependencies = true;
}
DiagnosticsNode toDiagnosticsNode({ String? name, DiagnosticsTreeStyle? style }) {
return _ElementDiagnosticableTreeNode(
name: name,
value: this,
style: style,
stateful: true,
);
}
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DiagnosticsProperty<State<StatefulWidget>>('state', _state, defaultValue: null));
}
}
StatefulElement通过持有state并对其生命周期进行管理。