1. 生命周期
一个对象从创建到销毁所经历的过程就是一个生命周期,说白了就是回调方法。在Flutter中已经封装好了,知道widget处于什么样的状态了,然后给你一个对应状态的回调,所以说生命周期其实是一系列的回调方法。
那么生命周期有什么作用呢?
2. Widget的生命周期
Widget主要分两种,StatelessWidget 和 StatefulWidget。这里先分析StatelessWidget的生命周期
2.1 StatelessWidget常见的生命周期
新建一个项目,然后在MyApp里面将home里面的widget改成Scaffold。
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(),
body: MyHomePage(title: 'Flutter Demo Page 2',),
),
);
}
}
然后将MyHomePage改成StatelessWidget,这里title是可选参数且允许为空,那么在使用的时候可以使用! 强制解包,或者使用?? 来让title为空的时候使用右边的值,那么这里不传title的话那么Text里面就会显示的是123。
class MyHomePage extends StatelessWidget {
final String? title;
MyHomePage({this.title});
@override
Widget build(BuildContext context) {
return Center(child: Text(title ?? "123"),);
}
}
然后在构造函数以及build函数里面添加打印,然后根据打印来看调用的顺序和时机。
class MyHomePage extends StatelessWidget {
final String? title;
MyHomePage({this.title}){
print('构造函数被调用了');
}
@override
Widget build(BuildContext context) {
print('build函数被调用了');
return Center(child: Text(title ?? "123"),);
}
}
这里android studio 运行的话会有小小的问题就是打印两次,用xcode运行就不会有这个问题了。这里可以看到构造函数是在build函数之前被调用的。
2.1 StatefulWidget常见的生命周期
将MyHomePage改成StatefulWidget,然后在Widget构造函数,createState函数,State构造函数,initState函数,dispose函数以及build函数里面分别添加打印方法。
class MyHomePage extends StatefulWidget {
final String? title;
MyHomePage({this.title}){
print('Widget构造函数被调用了');
}
@override
State<MyHomePage> createState() {
print('createState函数被调用了');
return _MyHomePageState();
}
}
class _MyHomePageState extends State<MyHomePage> {
_MyHomePageState() {
print('State构造函数被调用了');
}
@override
void initState() {
// TODO: implement initState
print('initState函数被调用了');
super.initState();
}
@override
void dispose() {
// TODO: implement dispose
print('dispose函数被调用了');
super.dispose();
}
@override
Widget build(BuildContext context) {
print('build函数被调用了');
return Scaffold(
appBar: AppBar(
),
body: Center(child: Text(widget.title ?? '123'),)
);
}
}
运行后观察打印顺序,发现是Widget构造函数 —— createState函数 —— State构造函数 —— initState函数 —— build函数 —— dispose函数,这里没有调用dispose函数是因为没有被销毁。 那么在setState的时候调用了哪些方法呢?修改一下_MyHomePageState。
class _MyHomePageState extends State<MyHomePage> {
int _count = 0;
_MyHomePageState() {
print('State构造函数被调用了');
}
@override
void initState() {
// TODO: implement initState
print('initState函数被调用了');
super.initState();
}
@override
void dispose() {
// TODO: implement dispose
print('dispose函数被调用了');
super.dispose();
}
@override
Widget build(BuildContext context) {
print('build函数被调用了');
return Column(
children: [
ElevatedButton(onPressed: (){
setState(() {
_count ++;
});
}, child: const Icon(Icons.add)),
Text('$_count'),
],
);
}
}
热重载后点击按钮,发现热重载调用了Widget构造函数和build函数。setState调用了build函数。 点进去setState的源码里面看到,setState其实只做了一件事就是_element!.markNeedsBuild()。 这里的_element是StatefulElement类型,并且在上面可以看到context就是_element。 那么是否可以通过调用markNeedsBuild来代替setState呢?实验一下
@override
Widget build(BuildContext context) {
print('build函数被调用了');
return Column(
children: [
ElevatedButton(onPressed: (){
_count ++;
(context as StatefulElement).markNeedsBuild();
}, child: const Icon(Icons.add)),
Text('$_count'),
],
);
}
运行后发现是可以的,并且屏幕上的text也有改变。当然这里还是推荐使用setState,因为系统在setState里面做了很多判断。 statefulWidget里面还有一个didChangeDependencies的回调方法。
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
super.didChangeDependencies();
}
会在initState函数和build函数之间被调用。didChangeDependencies是改变依赖关系的回调。 创建一个InheritedDemo部件来试验这个didChangeDependencies,这里设置多个层级test1,test2,test3。
import 'package:flutter/material.dart';
class InheritedDemo extends StatefulWidget {
const InheritedDemo({Key? key}) : super(key: key);
@override
_InheritedDemoState createState() => _InheritedDemoState();
}
class _InheritedDemoState extends State<InheritedDemo> {
int _count = 0;
@override
Widget build(BuildContext context) {
return Column(
children: [
Test1(_count),
ElevatedButton(onPressed: (){
setState(() {
_count++;
});
}, child: Text('我是按钮'))
],
);
}
}
class Test1 extends StatelessWidget {
final int count;
const Test1(this.count);
@override
Widget build(BuildContext context) {
// TODO: implement build
return Test2(count);
}
}
class Test2 extends StatelessWidget {
final int count;
const Test2(this.count);
@override
Widget build(BuildContext context) {
// TODO: implement build
return Test3(count);
}
}
class Test3 extends StatefulWidget {
final int count;
const Test3(this.count);
@override
_Test3State createState() => _Test3State();
}
class _Test3State extends State<Test3> {
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
print('didChangeDependencies来了');
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
print('build来了');
return Text(widget.count.toString());
}
}
到MyApp里面使用 InheritedDemo
home: Scaffold(
appBar: AppBar(),
body: InheritedDemo(
),
),
这个时候就可以共享count,但是这样方式太繁琐了,那么就创建一个MyData类。
class MyData extends InheritedWidget {
final int data;//需要在子组件中共享的数据(保存点击次数)
// 构造方法
const MyData({required this.data,required Widget child}):super(child: child);
// 定义一个便捷方法,方便子组件中的Widget 去获取共享的数据
static MyData? of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<MyData>();
}
// 该回调决定当前data发生变化的时候是否通知子组件依赖data的Widget
@override
bool updateShouldNotify(covariant MyData oldWidget) {
// 如果返回true,子部件中依赖数据的Widget(build函数中有使用数据)的didChangeDependencies会被调用
return oldWidget.data != data;
}
}
在_InheritedDemoState中使用MyData。
class _InheritedDemoState extends State<InheritedDemo> {
int _count = 0;
@override
Widget build(BuildContext context) {
return MyData(data: _count, child: Column(
children: [
Test1(_count),
ElevatedButton(onPressed: (){
setState(() {
_count++;
});
}, child: Text('我是按钮'))
],
));
}
}
那么这个时候,点击按钮的时候,就会调用didChangeDependencies函数 ,并且在build函数之前。如果updateShouldNotify返回false那么就不会调用didChangeDependencies函数。didChangeDependencies函数 主要是用在如果有很多逻辑依赖这个数据的情况下,那么就可以在didChangeDependencies保存这个数据。 在MyData里面的子部件才能共享数据,如果希望整个项目共享那么就在home里面就包 一个MyData。
3. 总结
- 生命周期的基本概念
- 什么是生命周期
- 说白了就是回调方法(函数)
- 让你知道我封装好的这个Widget它处于什么样的状态了!
- 有什么作用
- Widget的生命周期
- Stateless
- Stateful(包含两个对象Widget、State)
- Widget构造方法
- Widget的CreateState
- State的构造方法
- State的initState方法
- didChangeDependencies方法(改变依赖关系)
- 依赖的InheritedWidget发生变化之后,方法也会调用!
- State的build
- 当调用setState方法。会重新调用build进行渲染!
- 当Widget销毁的时候,调用State的dispose
|