原创:有趣知识点摸索型文章
创作不易,请珍惜,之后会持续更新,不断完善
个人比较喜欢做笔记和写总结,毕竟好记性不如烂笔头哈哈,这些文章记录了我的IOS成长历程,希望能与大家一起进步
温馨提示:由于简书不支持目录跳转,大家可通过command + F 输入目录标题后迅速寻找到你所需要的内容
目录
- 一、StatefulWidget 的状态管理
- 二、Flutter 默认 Demo 对 StatefulWidget 的使用
- 三、StatefulWidget 的生命周期
一、StatefulWidget 的状态管理
StatefulWidget 和 StatelessWidget 均继承自 Widget。
abstract class StatefulWidget extends Widget
abstract class StatelessWidget extends Widget
Widget上方有个注解:@immutable。该注解的意思就是不可变的意思,作用就是让 widget 及其子类是不可变的,定义的变量必须是 final 的,所以,这就导致无法在 StatelessWidget 内实现数据更新操作。
@immutable
abstract class Widget extends DiagnosticableTree
StatefulWidget 是相对于 StatelessWidget 实现可变的 widget。由于 StatefulWidget 也是继承于 widget,所以自然在 widget 内是做不了变量更新的。既然 Widget 是不可变,那么 StatefulWidget 如何来存储可变的状态呢?
StatelessWidget 无所谓,因为它里面的数据通常是直接定义完后就不修改的。但 StatefulWidget 需要有状态(可以理解成变量)的改变,这如何做到呢?
Flutter 将 StatefulWidget 设计成了两个类,也就是你创建 StatefulWidget 时必须创建两个类:一个类继承自 StatefulWidget,作为 Widget 树的一部分;另外一个类继承自 State,用于记录 StatefulWidget 会变化的状态,并且根据状态的变化,构建出新的 Widget。
基本结构如下:
class MyStatefulWidget extends StatefulWidget {
@override
State< MyStatefulWidget > createState() {
// 将创建的State返回
return MyState();
}
}
class MyState extends State<MyStatefulWidget> {
@override
Widget build(BuildContext context) {
return <构建自己的Widget>;
}
}
二、Flutter 默认 Demo 对 StatefulWidget 的使用
我们来看看系统为我们默认生成的页面中对 StatefulWidget 的使用。

这里有一个属性 title 表示的是页面的标题,其值由创建 MyHomePage 处赋予,在 State 的 build 方法中进行使用。像这样的属性,我们总是将其标记为 final。const MyHomePage({ })表示其初始方法,需要传入父类的属性和当前类中自定义的属性。
class MyHomePage extends StatefulWidget {
final String title;
const MyHomePage({super.key, required this.title});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
而其对应的继承自 State,用于记录 StatefulWidget 变化状态的类如下:
class _MyHomePageState extends State<MyHomePage> {
}
在其中我们新增加了一个变量 _counter,其初值为0,每当点击 + 按钮调用一次 _incrementCounter 方法就会让其值增加1。由于其值的改变是在 setState 中进行的,而当在 setState 中的值发生改变的时候,就会告诉 Flutter 框架当前状态发生了改变,这将导致它重新运行下面的构建方法 build。如果我们改变 _counter 却不调用 setState(),那么构建方法 build 将不会被再次调用,看起来什么都不会发生。
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
每次调用 setState 时都会重新运行下面这个方法。此处我们从 MyHomePage 对象中获取值,并使用它来设置我们的应用栏标题。
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
MyHomePage 对象是在 MyApp 的 build 方法中进行创建的。MyApp这个组件是我们应用程序的根组件。
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
在入口方法 main 方法中,系统调用了 runApp 方法,将 MyApp对象作为参数进入了传入。
void main() {
runApp(const MyApp());
}
总结 Flutter 自定义 StatefulWidget 的套路:
-
快捷代码模块:输入
stless、stful系统就会自动补全代码 -
自定义 Widget:继承自
StatefulWidget,重载createState方法来加载自定义的state -
自定义 State:继承自
State,实现你真正的UI部分和状态(Data)管理。自定义的State做状态管理,而setState做状态更新(更新完会触发Widget重新进行build)。
三、StatefulWidget 的生命周期
既然是个对象,就有生命流程。StatelessWidget 可以由父 Widget 直接传入值,调用 build 方法来构建,整个过程非常简单;而 StatefulWidget 需要通过 State 来管理其数据,并且还要监控状态的改变决定是否重新 build 整个 Widget,所以,我们主要讨论 StatefulWidget 的生命周期,也就是它从创建到销毁的整个过程。
1、StatefulWidget 类
class MyCounterWidget extends StatefulWidget {
}
执行 StatefulWidget 的构造函数(Constructor)来创建出 StatefulWidget。
MyCounterWidget() {
print("MyCounterWidget:执行了构造方法");
}
执行 StatefulWidget 的 createState 方法,来创建一个维护 StatefulWidget 的 State 对象
@override
State<StatefulWidget> createState() {
print("MyCounterWidget:执行了 createState 方法");
// 将创建的 State 返回
return MyCounterState();
}
2、State 类
class MyCounterState extends State<MyCounterWidget> {
}
执行 State 类的构造方法(Constructor)来创建 State 对象。
MyCounterState() {
print("MyCounterState:执行构造方法");
}
执行 initState。我们通常会在这个方法中执行一些数据初始化的操作,或者也可能会发送网络请求。
@override
void initState() {
super.initState();
print("MyCounterState:执行 init 方法");
}
注意这个方法是重写父类的方法,必须调用 super,因为父类中会进行一些其他操作。并且如果你阅读源码,你会发现这里有一个注解(annotation):@mustCallSuper。
@protected
@mustCallSuper
void initState() {
assert(_debugLifecycleState == _StateLifecycle.created);
}
执行 didChangeDependencies 方法,这个方法在两种情况下会调用。
-
情况一:调用
initState方法时会被调用 -
情况二:从其他对象中依赖一些数据发生改变时,比如
InheritedWidget
@override
void didChangeDependencies() {
super.didChangeDependencies();
print("MyCounterState:执行 didChangeDependencies 方法");
}
Flutter 执行 build 方法,来看一下我们当前的 Widget 需要渲染哪些 Widget。
@override
Widget build(BuildContext context) {
print("MyCounterState:执行 build 方法");
return Center( )
}
当前的 Widget 不再使用时,会调用 dispose 进行销毁。
@override
void dispose() {
super.dispose();
print("MyCounterState 执行 dispose 方法");
}
手动调用 setState 方法,会根据最新的状态(数据)来重新调用 build 方法,构建对应的 Widgets。
setState(() {
_counter++;
});
执行 didUpdateWidget 方法是在当父 Widget 触发重建(rebuild)时,系统会调用 didUpdateWidget 方法。
@override
void didUpdateWidget(MyCounterWidget oldWidget) {
super.didUpdateWidget(oldWidget);
print("MyCounterState:执行 didUpdateWidget 方法");
}
上面的代码直接运行,打印如下:
flutter: MyApp:build
flutter: MyCounterWidget:执行了构造方法
flutter: MyCounterWidget:执行了 createState 方法
flutter: MyCounterState:执行构造方法
flutter: MyCounterState:执行 init 方法
flutter: MyCounterState:执行 didChangeDependencies 方法
flutter: MyCounterState:执行 build 方法
注意这里 Flutter 会 build 所有的组件两次。如果你是用 Android Studio 开发的话,会有这个问题,但是如果使用 VSCode 进行开发则是正常的,即只会调用一遍的,所以不用太在意,可以理解为是 Android Studio 的 Bug,其运行到手机上肯定是正常的。
flutter: MyApp:build
flutter: MyCounterWidget:执行了构造方法
flutter: MyCounterState:执行 didUpdateWidget 方法
flutter: MyCounterState:执行 build 方法
当我们改变状态,手动执行 setState 方法后会打印如下结果:
flutter: MyCounterState:执行 build 方法