原创:有趣知识点摸索型文章
创作不易,请珍惜,之后会持续更新,不断完善
个人比较喜欢做笔记和写总结,毕竟好记性不如烂笔头哈哈,这些文章记录了我的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 方法
网友评论