生命周期的概念
什么是生命周期?
生命周期说白了就是回调的方法函数,让开发者知道当前的Widget处于什么样的状态
有什么作用?
监听Widget的事件
初始化数据:创建数据、发送网络请求
内存管理:销毁数据和监听者、销毁Timer等
Widget的生命周期
无状态的Stateless
构造方法
build方法
class SearchCell extends StatelessWidget {
// const SearchCell();
SearchCell(){
print('构造方法被调用');
};
@override
Widget build(BuildContext context) {
print('build方法被调用');
return Container();
}
有状态的Stateful(包含两个对象Widget、State)
Widget的构造方法
Widget的creatState
State的构造方法
State的initState方法
didChangeDependencies方法:改变依赖关系,依赖(共享数据)的InheritedWidget发生变化之后,方法也会调用
State的build方法,当调用setState方法,会重新调用build进行渲染
State的dispose方法,销毁时调用
class SearchPage extends StatefulWidget {
SearchPage(){
print('Widget的构造方法');
}
@override
_SearchPageState createState() {
print('Widget的CreatState');
return _SearchPageState();
}
}
class _SearchPageState extends State
_SearchPageState() {
print('State的构造方法');
}
@override
void initState() {
// TODO: implement initState
super.initState();
print('State的initState方法');
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
print('State的dispose方法');
}
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
super.didChangeDependencies();
print('didChangeDependencies方法');
}
@override
Widget build(BuildContext context) {
print('State的build方法');
return Container();
}
}
使用Flutter Hot Restart
[图片上传失败...(image-5ab0d0-1642498130005)]
使用Flutter Hot Reload
[图片上传失败...(image-23baba-1642498130005)]
-
setState
方法内部:
[图片上传失败...(image-155d01-1642498130005)]
_element
的类型:StatefulElement? _element;
BuildContext get context {
assert(() {
if (_element == null) {
throw FlutterError(
'This widget has been unmounted, so the State no longer has a context (and should be considered defunct). \n'
'Consider canceling any active work during "dispose" or using the "mounted" getter to determine if the State is still active.',
);
}
return true;
}());
return _element!;
}
StatefulElement? _element;
复制代码
从这里能够看出这里的_element
其实就是当前的context
,所以这也就是为什么调用setState
方法会重新走一遍build
的原因 => 等价代换如下:
context as StatefulElement;
context.markNeedsBuild();
复制代码
上面两行代码的效果和setState
是一样的!
-
InheritedWidget
数据共享
如果A的数据需要传递到B的话,我们之前是在构造方法里面传递,如下面的示例代码,这种的
didChangeDependencies
方法只会调用一次。
class InheritedDemo extends StatefulWidget {
const InheritedDemo({Key? key}) : super(key: key);
@override
_InheritedDemoState createState() => _InheritedDemoState();
}
class _InheritedDemoState extends State {
int _count = 0;
@override
Widget build(BuildContext context) {
return Column(
children: [
SizedBox(height: 200),
TextCount(count: _count),// _count通过组件的构造方法来传递
ElevatedButton(
onPressed: () {
_count++;
setState(() {});
},
child: Text('点我'),
)
],
);
}
}
class TextCount extends StatefulWidget {
final int count;
TextCount({required this.count});
@override
_TextCountState createState() => _TextCountState();
}
class _TextCountState extends State {
@override
Widget build(BuildContext context) {
return Text(widget.count.toString());
}
}
复制代码
这里我们介绍一个新的数据共享的方式InheritedWidget
,看一下该组件的内部方法还是比较简单的:
abstract class InheritedWidget extends ProxyWidget {
// 父类的构造方法
const InheritedWidget({ Key? key, required Widget child })
: super(key: key, child: child);
@override
InheritedElement createElement() => InheritedElement(this);
@protected
bool updateShouldNotify(covariant InheritedWidget oldWidget);
}
复制代码
-
- 首先定义一个共享数据类继承于该小部件
-
- 其次实现构造方法,该构造方法可以参考
InheritedWidget
抽象基类的方法
- 其次实现构造方法,该构造方法可以参考
-
- 最后定义一个类方法提供给外部使用来便捷获取数据
-
- 同时选择实现更新数据就去通知依赖共享数据的小部件
class MyData extends InheritedWidget {
final int count;
// 构造方法
const MyData({required this.count, required Widget child})
: super(child: child);
// 类方法提供给外部使用方便 拿到数据
static MyData? of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType();
}
// 数据发生变化时 是否通知
@override
bool updateShouldNotify(MyData oldWidget) {
return oldWidget.count != count;
}
}
复制代码
那怎么使用,才能把数据和组件关联上呢?
-
- 保存和关联:在build方法里面使用构造方法,拿到数据保存和关联也就是需要使用该数据的小部件
-
- 取出:在小部件需要使用的时候调用类方法拿出
class _InheritedDemoState extends State {
int _count = 0;
@override
Widget build(BuildContext context) {
return MyData( // 在这里使用
count: _count,
child: ....
);
}
}
class _TextCountState extends State {
@override
Widget build(BuildContext context) {
return Text(MyData.of(context)!.count.toString());
}
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
super.didChangeDependencies();
print('didChangeDependencies方法');
}
}
复制代码
此时每次点击的时候都会再次调用didChangeDependencies
方法
[图片上传失败...(image-befd2c-1642498130005)]
Widget的渲染原理
并不是所有的Widget
都会被独立渲染!只有集成RenderObjectWidget
的才会创建RenderObject
对象!在Flutter
渲染的流程中,有三个重要的树,Flutter
引擎是针对Render
树进行渲染!
-
Widget
树、Element
树、Render
树:每一个Widget
都会创建一个Element
对象。隐式调用creatElement
方法,Element
加入Element
树RenderElement
StatefulElement
StatelessElement
-
RenderElement
:主要是创建RenderObject
对象(继承RenderObjectWidget
的Widget
会创建RenderElement
)-
Fluter
会调用mount
方法,创建RanderObject
对象
-
-
StatefulElement
继承ComponentElement
(StatefulWidget
会创建StatefulElement
)- 调用creatState方法,创建State
- 将Widget赋值给state
state._widget = widget;
- 调用state的build方法并且将Element也就是自己本身传递出去
[图片上传失败...(image-48aeb3-1642498130004)]
-
StatelessElement
:继承ComponentElement
(StatelessWidget
会创建StatelessElement
)- Stateless会创建Element
- 然后Element创建就会调用mount方法
- mount里面会调用widget的bulid方法进行渲染,并且将Element自己本身传递出去
[图片上传失败...(image-97130c-1642498130004)]
作者:weak_PG