1. StatefulWidget
1.1. 认识StatefulWidget
在Flutter开发中,所有的widget都不能定义状态;
注意:widget
是@immutable
修饰的,所以继承wedget
的类内部是不能写变量的,只能用final
修饰;
• 创建一个单独的类,负责维护状态;
为什么 ?
• 这次因为Flutter在设计的时候就决定了一旦Widget中展示的数据发生变化,就重新构建整个Widget;
• Flutter通过一些机制来限定定义到Widget中的成员变量必须是final的;
为什么Flutter在设计的时候,StatefulWidget的build方法放在State中 ?
• 1. build出来的widget是需要依赖State中的变量(状态、数据);
• 2. 在flutter的运行过程中:
• widget是不断销毁和创建的;
• 当我们自己的状态发生改变时,并不希望创建一个新的state;
1.2. 案例展示
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: YZHomePage()
);
}
}
class YZHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("商品列表")
),
body: YZHomeContent("你好,李焕英")
);
}
}
class YZHomeContent extends StatefulWidget {
final String message;
YZHomeContent(this.message);
@override
_YZHomeContentState createState() => _YZHomeContentState();
}
class _YZHomeContentState extends State<YZHomeContent> {
int _counter = 0;
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_getButtons(),
Text("当前计数:$_counter", style: TextStyle(fontSize: 25),),
Text("传递过来的信息:${widget.message}")
],
),
);
}
Widget _getButtons(){
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RaisedButton(
child: Text("+", style: TextStyle(fontSize: 20, color: Colors.white)),
color: Colors.pink,
onPressed: () {
setState(() {
_counter++;
});
}
),
RaisedButton(
child: Text("-", style: TextStyle(fontSize: 20, color: Colors.white)),
color: Colors.purple,
onPressed: () {
setState(() {
_counter--;
});
}
)
],
);
}
}
1.3. StatefulWidget 的生命周期
1.3.1. 生命周期的理解
什么是生命周期呢?
客户端开发:iOS开发中我们需要知道UIViewController从创建到销毁的整个过程,Android开发中我们需要知道Activity从创建到销毁的整个过程。以便在不同的生命周期方法中完成不同的操作;
前端开发中:Vue、React开发中组件也都有自己的生命周期,在不同的生命周期中我们可以做不同的操作;
Flutter小部件的生命周期:
StatelessWidget可以由父Widget直接传入值,调用build方法来构建,整个过程非常简单;
class YZHomeContent extends StatelessWidget {
final Sting message;
YZHomeContent(this.message) {
print("构造函数被调用");
}
@override
Widget build(BuildContext context) {
print("调用build方法");
return Text(message);
}
}
而StatefulWidget需要通过State来管理其数据,并且还要监控状态的改变决定是否重新build整个Widget;
所以,我们主要讨论StatefulWidget的生命周期,也就是它从创建到销毁的整个过程;
1.3.2. StatefulWidget生命周期简单版
class YZhomeContent extends StatefulWidget {
@override
_YZhomeContentState createState() => _YZhomeContentState();
}
class _YZhomeContentState extends State<YZhomeContent> {
@override
Widget build(BuildContext context) {
return Container(
);
}
}
由上面代码中,我们知道StatefulWidget
本身由两个类组成:StatefulWidget
和State
;
首先,执行StatefulWidget中相关的方法:
- 执行
StatefulWidget
的构造函数(Constructor)来创建出StatefulWidget
;
- 执行
- 执行
StatefulWidget
的createState
方法,来创建一个维护StatefulWidget
的State
对象;
其次,调用createState
创建State
对象时,执行State
类相关方法;
- 执行
- 执行
State
类的构造方法(Constructor)来创建State
对象;
- 执行
- 执行
ininState
,我们通常会在这个方法中执行一些数据初始化的操作,或者也可能会发送网络请求;
- 执行
@protected
@mustCallSuper
void initState() {
assert(_debugLifecycleState == _StateLifecycle.created);
}
注意:这个方法是重写父类的方法,必须调用super
,因为父类中会进行一些其他操作;
并且如果你阅读源码,你会发现这里有一个注解(annotation):@mustCallSuper
-
执行
didChangeDependencies
方法,这个方法在两种情况下会调用- 情况一:调用
initState
会调用; - 情况二:从其他对象中依赖一些数据发生改变时,比如前面我们提到的
InheritedWidget
;
- 情况一:调用
-
- Flutter执行build方法,来看一下我们当前的Widget需要渲染哪些Widget;
- 当前的Widget不再使用时,会调用
dispose
进行销毁;
- 当前的Widget不再使用时,会调用
- 手动调用
setState
方法,会根据最新的状态(数据)来重新调用build
方法,构建对应的Widgets;
- 手动调用
- 执行
didUpdateWidget
方法是在当父Widget触发重建(rebuild)时,系统会调用didUpdateWidget
方法;
- 执行
class YZHomeContent extends StatefulWidget {
YZHomeContent(){
print("1.调用YZHomeContent的construction方法");
}
@override
_YZHomeContentState createState() {
print("2.调用YZHomeContent的createState方法");
return _YZHomeContentState();
};
}
class _YZHomeContentState extends State<YZHomeContent> {
_YZHomeContentState() {
print("3.调用YZHomeContentState的construction方法");
}
@override
void initState() {
// TODO: implement initState
super.initState();
print("4.调用_YZHomeContentState的initState方法");
}
@override
Widget build(BuildContext context) {
print("5.调用_YZHomeContentState的build");
return Container();
}
@override
void dispose() {
// TODO: implement dispose
print("6.调用_YZHomeContentState的dispose");
super.dispose();
}
}
1.3.3. 生命周期的复杂版
- mounted是State内部设置的一个属性,事实上我们不了解它也可以,但是如果你想深入了解它,会对State的机制理解更加清晰;
- 是内部设置的,不需要我们手动进行修改;
- dirty state的含义是脏的State
它实际是通过一个Element的东西的属性来标记的;
将它标记为dirty会等待下一次的重绘检查,强制调用build方法来构建我们的Widget;
- clean state的含义是干净的State
- 它表示当前build出来的Widget,下一次重绘检查时不需要重新build;