写了这么多,无非就是State文档贴过来,最有感触的就两点:
- State 的生命周期和 StatefulWidget 不同,当 StatefulWidget 状态改变后就会被重建,但是 State 不会改变,但是当 StatefulWidget 在 View 树中移除再插入又会生成新的 State。参考下文 State.context.
- initState -> build -> 状态改变 -> didUpdateWidget -> build --->移除.
在学习 flutter 的时候,总会用到 StatefulWidget,它是一个有状态的 widget,会根据不同状态有不同显示,它的生命周期与 State 有关,它的基本写法如下
// flutter官方教程里面的一个类,点击一个关注的星星,然后就表明已经关注。再点击表示不再关注,默认状态是已关注,关注数是41
class FavoriteWidget extends StatefulWidget {
@override
_FavoriteWidgetState createState() => new _FavoriteWidgetState();
}
class _FavoriteWidgetState extends State {
bool _isFavorited = true;
int _favoriteCount = 41;
void _toggleFavorite() {
setState(() {
// If the lake is currently favorited, unfavorite it. Otherwise, favorite it.
_favoriteCount = _isFavorited?_favoriteCount -1:_favoriteCount +1 ;
_isFavorited = !_isFavorited;
});
}
@override
Widget build(BuildContext context) {
return new Widget(
// build by states
);
}
}
将 FavoriteWidget 插入到 Views 树中的时候,每当调用 States.setState() 时,都会重新build一次FavoriteWidget ,然后将新的 Views代替原先的,并显示给用户。
您可能想知道为什么 StatefulWidget 和 State 是单独的对象。在 Flutter 中,这两种类型的对象具有不同的生命周期: Widget 是临时对象,用于构建当前状态下的应用程序,而 State 对象在多次调用
build()
之间保持不变,允许它们记住信息(状态)。
那么首先得知道,State的生命周期是什么?
一、生命周期
突然看到这个图,可能会有点懵,因为许多方法都不清是干什么的,稍后会慢慢讲解,不耐烦的可以跳到最后每个方法的总结,这里先总体介绍一下生命周期,大致可以看成三个阶段:
- 初始化(插入渲染树)
- 状态改变(在渲染树中存在)
- 销毁(从渲染树种移除)
先举 FavoriteWidget
为例,当这个 Widget 首次插入到树中时,框架会调用其 createState
函数以创建一个新的_FavoriteWidgetState
实例来与该树中的相应位置关联(请注意,我们通常命名State子类时带一个下划线,这表示其是私有的)。 当这个widget的父级重建时,父级将创建一个新的FavoriteWidget
实例,但是Flutter框架将重用已经在树中的_FavoriteWidgetState
实例,而不是再次调用createState
创建一个新的。
从 StatefulWidget 调用createState之后,框架将新的状态对象插入树中,然后调用 State 的initState
,接着如上图所示走了一遍自身的生命周期。需要注意的是,StatefulWidget 和 State 是不同的生命周期。
二、State 源文档翻译
State 是当 Widget 被渲染或者在其生命周期中状态改变时,能同步读到相关信息的对象。当实例StatefulWidget 时(下文说的 Widget 无特别说明,都是StatefulWidget 懒得打),必须保证能正确使用 State.setState 来告知该 Widget的状态发生了变化。
当渲染这个 Widget 并将其插入View 树中,会调用 StatefulWidget.createState 然后,framework 就会创建一个 State 对象。 因为一个 Widget 可以被 inflated 多次,比如说 这个 FavoriteWidget 可以被多个地方用到,所以这里会存在多个 _FavoriteWidgetState 与之绑定。同样,当 Widget 被移除出 Views 树的时候,然后又重新插入,这时候 framework 会再次调用StatefulWidget.createState 来创建一个新的 State 对象。
State 的生命周期如下:
The framework creates a State object by calling StatefulWidget.createState.
这个新的 State 对象将会绑定一个 BuildContext ,这个绑定是永久的。 State 永远也不会改变其 BuildContext (所以它的属性中,contenxt是只读的。可以把这个理解成 Widget 在 Views 树中的位置,文档中是 The location in the tree where this widget builds.)但是, BuildContext 自身却是可以改变的,可以因为 Widget 在树中的位置变化而变化。由此,State 有一个属性是 mounted 表明 State 当前是否正确绑定在View树中。当创建 State 对象,并在调用 State.initState 之前,framework 会根据 BuildContext 来标记 mounted,然后在 State的生命周期里面,这个 mounted 属性不会改变,直至 framework 调用 State.dispose,当改变之后, State 对象再也不会调用 build 方法,而且当 mounted = false 时,调用 State.setState 会报错。
The framework calls initState. 在State 生命周期中只会调用一次。
The framework calls didChangeDependencies. 一般是在初始化中调用,但是如果BuildContext.inheritFromWidgetOfExactType 被调用,那么当widgets 改变或者是在 Views 树中移动,didChangeDependencies将会再一次调用。
当 State 完全初始化后,framework 会多次调用 build来获取绑定的实例化 Widget 的信息。同时,当调用 setState 方法时,State 会自发的重建 Widget 的子 Views。
During this time, a parent widget might rebuild and request that this location in the tree update to display a new widget with the same runtimeType and Widget.key.When this happens, the framework will update the widget property to refer to the new widget and then call the didUpdateWidget method with the previous widget as an argument. State objects should override didUpdateWidget to respond to changes in their associated widget (e.g., to start implicit animations). The framework always calls build after calling didUpdateWidget, which means any calls to setState in didUpdateWidget are redundant.
During development, if a hot reload occurs (whether initiated from the command line
flutter
tool by pressingr
, or from an IDE), the reassemble method is called. This provides an opportunity to reinitialize any data that was prepared in the initState method.f the subtree containing the State object is removed from the tree (e.g., because the parent built a widget with a different runtimeType or Widget.key), the framework calls the deactivate method. Subclasses should override this method to clean up any links between this object and other elements in the tree (e.g. if you have provided an ancestor with a pointer to a descendant's RenderObject).
At this point, the framework might reinsert this subtree into another part of the tree. If that happens, the framework will ensure that it calls build to give the State object a chance to adapt to its new location in the tree. If the framework does reinsert this subtree, it will do so before the end of the animation frame in which the subtree was removed from the tree. For this reason, State objects can defer releasing most resources until the framework calls their dispose method.
If the framework does not reinsert this subtree by the end of the current animation frame, the framework will call dispose, which indicates that this State object will never build again. Subclasses should override this method to release any resources retained by this object (e.g., stop any active animations).
After the framework calls dispose, the State object is considered unmounted and the mountedproperty is false. It is an error to call setState at this point. This stage of the lifecycle is terminal: there is no way to remount a State object that has been disposed.
名称 | 返回值/类型 | 意义 |
---|---|---|
context read-only | BuildContext | The location in the tree where this widget builds. |
mounted read-only | bool | Whether this State object is currently in a tree. |
widget read-only | T | The current configuration. |
hashCode read-only, inherited | int | The hash code for this object. |
runtimeType read-only, inherited | Type | A representation of the runtime type of the object. |
build(BuildContext context) | Widget | Describes the part of the user interface represented by this widget. |
deactivate() | void | Called when this object is removed from the tree. |
debugFillProperties(DiagnosticPropertiesBuilder properties) | void | Add additional properties associated with the node. |
didChangeDependencies() | void | Called when a dependency of this State object changes. |
didUpdateWidget(T oldWidget) | void | Called whenever the widget configuration changes. |
dispose() | void | Called when this object is removed from the tree permanently. |
initState() | void | Called when this object is inserted into the tree. |
reassemble() | void | Called whenever the application is reassembled during debugging, for example during hot reload. |
setState (VoidCallback fn) | void | Notify the framework that the internal state of this object has changed. |
参考资料:
https://docs.flutter.io/flutter/widgets/State-class.html
https://segmentfault.com/a/1190000015211309 推举