Widget生命周期
生命周期的基本概念
* 什么是生命周期
* 说白了就是回调方法(函数)
* 让使用者知道封装好的Widget当前处于什么状态
* 有什么作用
* 监听Widget的事件
* 初始化数据
* 创建数据
* 发送网络请求
* 内存管理
* 销毁数据、销毁监听者
* 销毁Timer等等
查看无状态小部件的生命周期
// 忽略当前文件未使用key的报警
// ignore_for_file: use_key_in_widget_constructors, avoid_print
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
Row;
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(),
body: MyHomePage(title: 'Flutter Demo Page2'),
),
);
}
}
class MyHomePage extends StatelessWidget {
final String? title;
MyHomePage({this.title}) {
print('构造函数被调用了!');
}
Widget build(BuildContext context) {
print('build方法被调用了!');
// 上面title不传的话,默认展示123,这就是flutter中的空安全
return Center(child: Text(title ?? '123'));
}
}

热重载的时候生命周期执行了一次。
问题:重新运行发现生命周期执行了两次

实际上只执行了一次,多出来的一次是Android Studio的问题,我们不用担心。下面通过其他工具进行验证
- 通过
Xcode运行查看日志进行验证 - 使用终端执行
$ flutter run -d 'iphone 12'进行验证

查看有状态小部件的生命周期
// 忽略当前文件未使用key的报警
// ignore_for_file: use_key_in_widget_constructors, avoid_print
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
Row;
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(),
body: MyHomePage(title: 'Flutter Demo Page2'),
),
);
}
}
class MyHomePage extends StatefulWidget {
final String? title;
MyHomePage({this.title}) {
print('Widget构造函数被调用了!');
}
@override
_MyHomePageState createState() {
// TODO: implement createState
print('createState来了!');
return _MyHomePageState();
}
}
// <MyHomePage>表示是MyHomePage对象的State
class _MyHomePageState extends State<MyHomePage> {
_MyHomePageState() {
print('State的构造方法');
}
@override
void initState() {
print('State的init方法');
super.initState();
}
Widget build(BuildContext context) {
print('State的build方法被调用了!');
// 上面title不传的话,默认展示123,这就是flutter中的空安全
return Center(child: Text(widget.title ?? '123'));
}
@override
void dispose() {
print('State的dispose');
super.dispose();
}
}

State也是有状态的,它需要更新数据,当State状态发生变化,又是怎样的呢?下面给State添加数据
// <MyHomePage>表示是MyHomePage对象的State
class _MyHomePageState extends State<MyHomePage> {
int _count = 0;
_MyHomePageState() {
print('State的构造方法');
}
@override
void initState() {
print('State的init方法');
super.initState();
}
@override
Widget build(BuildContext context) {
print('State的build方法被调用了!');
return Column(
children: [
ElevatedButton(
onPressed: () {
_count++;
setState(() {});
},
child: const Icon(Icons.add)),
Text('$_count')
],
);
}
@override
void dispose() {
print('State的dispose');
super.dispose();
}
}


点击之后只有State的build方法被调用了,也就是每次调用setState都会重新调用build方法。进入setState查看源码,主要方法是markNeedsBuild(),把setState(() {});替换成调用markNeedsBuild(),点击+号按钮依然能够触发State的build方法被调用了!。

数据共享InheritedWidget
有状态小部件还有一个生命周期方法didChangeDependencies
class _MyHomePageState extends State<MyHomePage> {
int _count = 0;
_MyHomePageState() {
print('State的构造方法');
}
@override
void initState() {
print('State的init方法');
super.initState();
}
@override
Widget build(BuildContext context) {
print('State的build方法被调用了!');
return Column(
children: [
ElevatedButton(
onPressed: () {
_count++;
setState(() {});
},
child: const Icon(Icons.add)),
Text('$_count')
],
);
}
@override
void dispose() {
print('State的dispose');
super.dispose();
}
@override
void didChangeDependencies() {
print('didChangeDependencies');
super.didChangeDependencies();
}
}

didChangeDependencies方法的调用在build调用之前,主要用于改变依赖关系;说到依赖关系,我们就不得不提InheritedWidget数据共享小部件
- 新建
inherited_demo.dart文件
<!-- main.dart文件 -->
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
Row;
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(),
// 使用InheritedDemo小部件
body: const InheritedDemo(),
),
);
}
}
<!-- inherited_demo.dart文件 -->
import 'package:flutter/material.dart';
class InheritedDemo extends StatefulWidget {
const InheritedDemo({Key? key}) : super(key: key);
@override
_InheritedDemoState createState() => _InheritedDemoState();
}
class _InheritedDemoState extends State<InheritedDemo> {
int _count = 0;
@override
Widget build(BuildContext context) {
return Column(
children: [
Test1(_count),
ElevatedButton(
onPressed: () {
_count++;
setState(() {});
},
child: const Text('我是按钮'))
],
);
}
}
class Test1 extends StatelessWidget {
final int count;
const Test1(this.count);
@override
Widget build(BuildContext context) {
return Test2(count);
throw UnimplementedError();
}
}
class Test2 extends StatelessWidget {
final int count;
const Test2(this.count);
@override
Widget build(BuildContext context) {
return Test3(count);
throw UnimplementedError();
}
}
class Test3 extends StatefulWidget {
final int count;
const Test3(this.count);
@override
_Test3State createState() => _Test3State();
}
class _Test3State extends State<Test3> {
@override
void didChangeDependencies() {
print('didChangeDependencies来了');
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
return Text(widget.count.toString());
}
}

重新运行工程didChangeDependencies方法执行了一次,点击按钮didChangeDependencies方法并没有执行。
- 创建
数据共享类
// 使用共享类,子组件之间就能共享数据
class _InheritedDemoState extends State<InheritedDemo> {
int _count = 0;
@override
Widget build(BuildContext context) {
// MyData共享类
return MyData(
data: _count,
child: Column(
children: [
Test1(_count),
ElevatedButton(
onPressed: () {
_count++;
setState(() {});
},
child: const Text('我是按钮'))
],
)
);
}
}
// 使用了MyData的子组件才会依赖data的Widget
class _Test3State extends State<Test3> {
@override
void didChangeDependencies() {
print('didChangeDependencies来了');
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
print('哥么我来了!');
// 使用了MyData的子组件才会依赖data的Widget
return Text(MyData.of(context)!.data.toString());
}
}
// 数据共享类
class MyData extends InheritedWidget {
final int data; //需要在子组件中共享的数据(保存点击次数)
//构造方法
const MyData({required this.data, required Widget child})
: super(child: child);
//定义一个便捷方法,方便子组件中的Widget去获取共享的数据
static MyData? of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<MyData>();
}
//该回调决定当前data发生变化时,是否通知子组件依赖data的Widget
@override
bool updateShouldNotify(MyData oldWidget) {
//如果返回true,子部件中依赖数据的Widget(build函数中有数据)的didChangeDependencies会调用!
return oldWidget.data != data;
}
}

小结:Widget的生命周期
* StatelessWidget
* 1. 构造方法
* 2. build方法
* StatefulWidget(包含两个对象Widget 、State)
* Widget构造方法
* Widget的CreateState
* State的构造方法
* State的initState方法
* didChangeDependencies方法(改变依赖关系)
* 依赖(共享数据)的InheritedWidget发生变化之后,didChangeDependencies方法才会调用!
* State的build
* 当调用setState方法,会重新调用build进行渲染!
* setState方法内部主要是利用_element(本质就是context对象)调用markNeedsBuild()
* 当Widget销毁的时候,调用State的dispose方法
Widget树与Render树
Widget的渲染原理
并不是所有的Widget都会被独立渲染,只有继承了RenderObjectWidget才会创建RenderObject对象;在Flutter渲染的流程中,有三棵重要的树,Flutter引擎是针对Render树进行渲染。
Widget树、Element树、Render树
Widget Tree
Widget Tree是整个UI界面的配置,Flutter开发者通过Widget Tree告诉Framework想要绘制的UI界面是什么样的,这棵树是我们主要打交道的对象。Element Tree
Element Tree是通过Widget Tree生成的,其主要作用是维护UI元素的树形结构,并将Widget和RenderObject关联到树上。RenderObject Tree
RenderObject Tree也是通过Widget Tree生成的,其主要作用是负责界面的绘制和布局,是属于底层系统,Flutter开发者一般不需要直接操作该树。

Element树
查看Element定义,发现它也是一个抽象类:
abstract class Element extends DiagnosticableTree implements BuildContext {
Element(Widget widget)
: assert(widget != null),
_widget = widget;
Element _parent;
@override
Widget get widget => _widget;
Widget _widget;
RenderObject get renderObject { ... }
@mustCallSuper
void mount(Element parent, dynamic newSlot) { ... }
@mustCallSuper
void activate() { ... }
@mustCallSuper
void deactivate() { ... }
@mustCallSuper
void unmount() { ... }
StatefulElement和StatelessElement继承自ComponentElement, ComponentElement是继承自Element的抽象类。
abstract class ComponentElement extends Element { ... }
Element的生命周期:
Framework调用Widget.createElement创建一个Element实例,记为element;Framework调用element.mount(parentElement,newSlot),mount方法中首先调用element所对应Widget的createRenderObject方法创建与element相关联的RenderObject对象,然后调用element.attachRenderObject方法将element.renderObject添加到渲染树中插槽指定的位置(这一步不是必须的,一般发生在Element树结构发生变化时才需要重新attach)。插入到渲染树后的element就处于“active”状态,处于“active”状态后就可以显示在屏幕上了(可以隐藏)。当有父
Widget的配置数据改变时,同时其State.build返回的Widget结构与之前不同,此时就需要重新构建对应的Element树。为了进行Element复用,在Element重新构建前会先尝试是否可以复用旧树上相同位置的element,element节点在更新前都会调用其对应Widget的canUpdate方法,如果返回true,则复用旧Element,旧的Element会使用新Widget配置数据更新,反之则会创建一个新的Element。Widget.canUpdate主要是判断newWidget与oldWidget的runtimeType和key是否同时相等,如果同时相等就返回true,否则就会返回false。根据这个原理,当我们需要强制更新一个Widget时,可以通过指定不同的Key来避免复用。当有祖先
Element决定要移除element时(如Widget树结构发生了变化,导致element对应的Widget被移除),这时该祖先Element就会调用deactivateChild 方法来移除它,移除后element.renderObject也会被从渲染树中移除,然后Framework会调用element.deactivate方法,这时element状态变为inactive状态。inactive态的element将不会再显示到屏幕。为了避免在一次动画执行过程中反复创建、移除某个特定element,inactive态的element在当前动画最后一帧结束前都会保留,如果在动画执行结束后它还未能重新变成active状态,Framework就会调用其unmount方法将其彻底移除,这时element的状态为defunct,它将永远不会再被插入到树中。如果element要重新插入到Element树的其它位置,如
element或element的祖先拥有一个GlobalKey(用于全局复用元素),那么Framework会先将element从现有位置移除,然后再调用其activate方法,并将其renderObject重新attach到渲染树。
StatelessWidget的Element
通过源码分析StatelessWidget的Element




Flutter断点调试源码的方式


StatefulWidget的Element

class StatefulElement extends ComponentElement {
StatefulElement(StatefulWidget widget)
: _state = widget.createState(),
super(widget) {
...
_state._element = this;
_state._widget = widget;
...
}
State<StatefulWidget> get state => _state;
State<StatefulWidget> _state;
...
@override
Widget build() => state.build(this);
...
}
在创建StatefulElement实例时,会调用widget.createState()赋给私有变量_state,同时把widget和element赋给_state,从而三者产生关联关系,它的build方法就是调用state.build(this),这里的this就是StatefulElement对象自己。
小结:Widget树、Element树、Render树
* 每一个Widget创建的时候都会创建一个Element对象
* 调用createElement方法,Element加入Element树中,都会调用mount方法
* RenderElement主要是创建RenderObject对象
* 通过mount方法创建RenderObject对象
* StatefulElement继承ComponentElement
* 调用createState方法,创建state
* 将Widget赋值给State对象
* 调用state的build方法,并且将自己(Element)传出去
* StatelessElement继承ComponentElement
* StatelessWidget会创建Element
* 然后Element创建就会调用mount方法
* mount里面会调用Widget的build方法进行渲染,并且将Element自己传出去
* 主要调用build方法,并且将自己(Element)传出去