Flutter运行机制

Widget树与渲染树

Flutter中Widget树相当于一段不可变的渲染描述信息,Widget树会告诉Flutter如何渲染UI,而渲染树才是真正的渲染层次结构。

例如下列代码:

1
2
3
4
5
6
7
8
9
10
11
Widget build(BuildContext context) {
return Column(
children: [
Text("Hello, Flutter"),
ElevatedButton(
onPressed: () {},
child: Text("Click Me"),
),
],
);
}

这里的Column及其子组件Text/ElevatesButton组成了一棵Widget树,这棵树会被Flutter解析为一个渲染树,随后渲染到屏幕上。
但这是一颗静态的树,如果我们需要动态更新UI,就需要使用StatefulWidget。

StatefulWidget与StatelessWidget

StatelessWidget很好理解,像上面那个例子,Text和ElevatedButton是不会改变的,所以我们可以使用StatelessWidget。
而内部包含可变状态的组件就是StatefulWidget,StatefulWidget内部包含一个State对象,这个State对象是可变的,可以通过setState方法来更新UI。
每当调用setState方法时,Flutter会调用State对象的build方法来重建UI,此时widget树会被重新构建,但渲染树不会被重新构建,渲染树只会被更新。

例如下列代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class MyWidget extends StatefulWidget {
@override
_MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
int _counter = 0;

void _increment() {
setState(() {
_counter++;
});
}

@override
Widget build(BuildContext context) {
return Column(
children: [
Text("$_counter"),
ElevatedButton(
onPressed: _increment,
child: Text("Click Me"),
),
],
);
}
}

当widget树被创建后之后,用户通过点击事件更新_counter的值时,widget树会被重建,但是屏幕上的渲染树会通过diff对比发现,只有
Text中的值发生了变化,所以只有Text部分会被更新,而ElevatedButton部分不会被更新。这样的更新方式会极大地提高性能。

比较 Widget树 渲染树
作用 描述UI结构 负责布局绘制
可变性 不可变 可变
更新 重建 更新
关系 用户编写 Flutter维护

生命周期

statelessWidget显然没有太多的生命周期,所以这里的生命周期只和StatefulWidget有关。
常用的那几个生命周期方法如下:

  • initState:初始化状态,只会调用一次
  • didChangeDependencies:当State对象的依赖发生变化时会被调用
  • build:构建Widget树
  • didUpdateWidget:当Widget重新构建时,Flutter会调用Widget.canUpdate来检测Widget树中同一位置的新旧节点,然后决定是否需要更新,如果Widget.canUpdate返回true则会调用此回调
  • deactivate:当State对象从树中被移除时会调用
  • dispose:当State对象从树中被永久移除时会调用
  • reassemble:热重载时会调用
  • setState:调用时会触发build方法