1.生命周期的基本概念
生命周期就是一系列的回调函数
每个函数让你知道当前这个Widget处于什么状态
2.生命周期的作用
监听Widget的事件
初始化数据 创建数据 发送网络请求
内存管理 销毁数据、监听者 销毁Timer
3.StatelessWidget
4.StatefulWidget(包含State)
Widget构造方法
Widget的createState
State的构造方法
State的initState
方法
didChangeDependencies
依赖的InheritedWidget
发送变化时会调用
State的build
方法 当调用setState
方法。会重新调用build
进行渲染
当Widget销毁的时候,调用State的dispose
class Home extends StatefulWidget {
Home() {
print('Home构造方法调用了');
}
@override
// ignore: no_logic_in_create_state
_HomeState createState() {
print('createState调用了');
return _HomeState();
}
}
class _HomeState extends State {
int _count = 0;
_HomeState() {
print('_HomeState构造方法调用了');
}
@override
void initState() {
print('initState调用了');
super.initState();
}
@override
void didChangeDependencies() {
print('didChangeDependencies调用了');
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
print('State中build调用了');
return Column(
children: [
Text('$_count'),
ElevatedButton(onPressed: () {
_count ++;
setState(() {});
}, child: const Icon(Icons.add))
],
);
}
@override
void dispose() {
print('dispose调用了');
super.dispose();
}
}
5.关于didChangeDependencies&InheritedWidget数据共享
依赖的InheritedWidget发送变化时会调用
这里需要使用到一个新的类,InheritedWidget
class MyData extends InheritedWidget {
final int data;
//子类的构造方法里必须要有child,必须将child传给super进行赋值
MyData({required this.data, required Widget child}) : super(child: child);
//定义一个外界获取共享数据时需要调用的方法
static MyData? of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType();
}
/* 是否需要通知依赖该数据的子部件刷新
* 如果子部件为StatelessWidget,无论返回true或false,执行构造函数和build。刷新视图
*
* 如果返回false,子部件为StateulWidget,不会执行didChangeDependencies,
* 不会执行其它函数,Widget不会发生任何变化。
* 如果返回true,子部件为StateulWidget,执行didChangeDependencies。
* 然后执行build刷新Widget。
* */
@override
bool updateShouldNotify(covariant MyData oldWidget) {
return oldWidget.data != data;
}
}
class Home extends StatefulWidget {
@override
// ignore: no_logic_in_create_state
_HomeState createState() {
print('createState调用了');
return _HomeState();
}
}
class _HomeState extends State {
int _count = 0;
@override
void didChangeDependencies() {
print('didChangeDependencies调用了');
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
return MyData(data: _count, child: MaterialApp(
home: Scaffold(
appBar: AppBar(title: AppBarTitle()),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
const TopText(),
CenterText(),
Button(increase: () {
_count ++;
(context as StatefulElement).markNeedsBuild();
},)
],
),
),
));
}
}
class AppBarTitle extends StatelessWidget {
AppBarTitle({Key? key}) : super(key: key) {
print('AppBarTitle 构造');
}
/*
* StatelessWidget
* 这里的AppBarTitle为StatelessWidget,没有didChangeDependencies
* 因此上层视图刷新后,该Widget会重新创建,然后执行build
* */
@override
Widget build(BuildContext context) {
return Text(MyData.of(context)!.data.toString());
}
}
class TopText extends StatefulWidget {
const TopText({Key? key}) : super(key: key);
@override
_TopTextState createState() => _TopTextState();
}
class _TopTextState extends State {
_TopTextState() {
print('_TopTextState 构造');
}
/*
* StatefulWidget
* 当_count改变后,执行_HomeState的build方法,不会执行_TopTextState构造函数。
* 执行到didChangeDependencies然后执行build
* */
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
super.didChangeDependencies();
print('didChangeDependencies');
}
@override
Widget build(BuildContext context) {
print('TopText build');
return Center(
child: Text(MyData.of(context)!.data.toString()),
);
}
}
class CenterText extends StatelessWidget {
CenterText() {
print('CenterText 构造');
}
@override
Widget build(BuildContext context) {
print('CenterText build');
return const Center(
child: Text('CenterText'),
);
}
}
class Button extends StatefulWidget {
void Function()? increase;
Button({this.increase});
@override
State createState() => _ButtonState();
}
class _ButtonState extends State {
@override
Widget build(BuildContext context) {
print('_ButtonState build');
return ElevatedButton(onPressed: () {
if (widget.increase != null) {
widget.increase!();
}
}, child: const Icon(Icons.add));
}
}
InheritedWidget将State作为保存数据,来实现当父部件刷新时,某一些子部件不刷新的功能
例如MyData中data存放的是_HomeState(之前是_HomeState,去除私有)
通过HomeState来获取count赋值
注意:updateShouldNotify
出现了新的关键字 convariant
这里写了个小demo来解释一下convariant的用法及作用
class People {
//和另一个人交谈
chatWith(People p){}
}
class Teacher extends People {
@override
//如果不加covariant,会抛出异常。编译器强制要你使用People而不是Teacher
chatWith(covariant Teacher t) {
// TODO: implement chatWith
print('这个老师正在和${t.getName()}聊天');
}
getName() {
return '李老师';
}
}
void main() {
Teacher().chatWith(Teacher()); // 这个老师正在和李老师聊天
}
总结来说,covariant字义为协变,即我和编译器协商,这个参数缩窄变化是我故意这样做的,你别抛异常了
6.通过InheritedWidget实现子部件不执行Rebuild
实现当父部件rebuild并且子部件不需要rebuild时的需求
class MyData extends InheritedWidget {
final HomeState data;
//子类的构造方法里必须要有child,必须将child传给super进行赋值
MyData({required this.data, required Widget child}) : super(child: child);
//定义一个外界获取共享数据时需要调用的方法
static MyData? of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType();
}
@override
bool updateShouldNotify(covariant MyData oldWidget) {
return true;
}
}
void main() {
runApp(MaterialApp(
home: Home(child: Scaffold(
appBar: AppBar(title: AppBarTitle()),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
TopText(),
CenterText(),
Button()
],
),
),),
));
}
class Home extends StatefulWidget {
final Widget child;
//1.在Home里保存传入进来的Widget
Home({required this.child});
@override
// ignore: no_logic_in_create_state
HomeState createState() {
print('createState调用了');
return HomeState();
}
}
class HomeState extends State {
int count = 0;
increase() {
setState(() {
count ++;
});
}
@override
void didChangeDependencies() {
print('didChangeDependencies调用了');
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
//2.将传入的child赋值给InheritedWidget子类(这里是MyData)
return MyData(data: this, child:widget.child);
}
}
class AppBarTitle extends StatelessWidget {
AppBarTitle({Key? key}) : super(key: key) {
print('AppBarTitle 构造');
}
@override
Widget build(BuildContext context) {
return Text(MyData.of(context)!.data.count.toString());
}
}
class TopText extends StatefulWidget {
const TopText({Key? key}) : super(key: key);
@override
_TopTextState createState() => _TopTextState();
}
class _TopTextState extends State {
_TopTextState() {
print('_TopTextState 构造');
}
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
super.didChangeDependencies();
print('didChangeDependencies');
}
@override
Widget build(BuildContext context) {
print('TopText build');
return Center(
child: Text(MyData.of(context)!.data.count.toString()),
);
}
}
class CenterText extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('CenterText build');
return const Text('CenterText');
}
}
class Button extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('_ButtonState build');
return ElevatedButton(onPressed: () {
MyData.of(context)!.data.increase();
}, child: const Icon(Icons.add));
}
}
点击按钮时,通过控制台/Flutter Performance
查看加载情况
CenterText不会rebuild
7.关于setState
进入setState源码,将asset相关的代码折起来。
除去assert后,发现只执行了一句代码_element!.markNeedsBuild();
标记为脏元素,将_element加入_dirtyElements
void setState(VoidCallback fn) {
assert(fn != null);
assert(...);
final Object? result = fn() as dynamic;
assert(...);
_element!.markNeedsBuild();
}
查看源码得知,build函数中的context
其实就是_element
BuildContext get context {
assert(() {
if (_element == null) {
throw FlutterError(
'This widget has been unmounted, so the State no longer has a context (and should be considered defunct). \n'
'Consider canceling any active work during "dispose" or using the "mounted" getter to determine if the State is still active.',
);
}
return true;
}());
return _element!;
}
StatefulElement? _element;
因此setState也就可以改为(context as StatefulElement).markNeedsBuild()
Widget build(BuildContext context) {
print('State中build调用了');
return Column(
children: [
Text('$_count'),
ElevatedButton(onPressed: () {
_count ++;
(context as StatefulElement).markNeedsBuild();
}, child: const Icon(Icons.add))
],
);
}