亮再不能兴兵讨贼,悠悠苍天何薄于我。——诸葛亮
疫情比过年的时候好转多了,生活的雾也渐渐淡了,看到的是美好。
平常还是比较宅,除了工作之外就是一股劲的坐在电脑前捣鼓新的技术。虽然我对一门技术没有很深的研究,但是并不意味我对技术不感兴趣;也许不久的将来我能在技术的某个点上足够的深入。其实人到中年这句话在程序员的耳边响起了无数回,也许真的那一天会来,到时你是在靠努力加班度中年还是靠自身的技术过硬寻求一份靠谱的职位。从接触Java到安卓原生开发(Java&Kotlin)再到Flutter,每一个技术只是一个过渡,不难发现原理始终未变。我时常在想我何时拥有了什么样的技术才能成为别人眼中的大佬呢??孩子别做梦了,冰冻三尺非一日之寒。你若在某个点上很牛,但是你的面又不广;你若面很广,但是你也得有一门很有含金量的技术。看过武侠剧的都知道乔峰为何会各种武功又精通降龙十八掌,不愧为一代帮主呀。作为程序员也得会很多,但是至少有一样是你擅长的。
接触原生开发的时候,我们经常打交道最多的就是activity生命周期。
Flutter在界面布局上可以统一安卓和苹果两端,在页面呈现和交互上,任然需要考虑生命周期。
创建两个page 观察StatefulWidget生命周期变化
当第一个page被创建,生命周期函数执行如下:
I/flutter (....): BaseWidgetState__HomePageWidgetState_initState
I/flutter (....): BaseWidgetState__HomePageWidgetState_didChangeDependencies
I/flutter (....): BaseWidgetState__HomePageWidgetState_build
.initState:数据初始化
The framework calls initState. Subclasses of State should override initState to perform one-time initialization that depends on the BuildContext or the widget, which are available as the context and widget properties, respectively, when the initState method is called.
framework调用initState函数。State的子类取决于上下文或widget应该重写initState函数执行数据初始化,当initState函数被调用时分别初始化作为上下文和widget可用的属性值。
大概的使用:就是initState初始化的属性值可用作为与当前state关联的类以及当前widget使用;
.didChangeDependencies
The framework calls didChangeDependencies. Subclasses of State should override didChangeDependencies to perform initialization involving InheritedWidgets. If BuildContext.dependOnInheritedWidgetOfExactType is called, the didChangeDependencies method will be called again if the inherited widgets subsequently change or if the widget moves in the tree.
framework调用didChangeDependencies函数。State的子类重新didChangeDependencies用来执行与InheritedWidgets关联的widget初始化。如果执行BuildContext.dependOnInheritedWidgetOfExactType,如果继承自InheritedWidgets的小部件属性值变化或移动,didChangeDependencies方法将再次被调用。
根据官网原话:didChangeDependencies很少被重写,widget重写绘制会调用build函数,使用didChangeDependencies成本太大(可用于获取网络状态等)。
.build
At this point, the State object is fully initialized and the framework might call its build method any number of times to obtain a description of the user interface for this subtree. State objects can spontaneously request to rebuild their subtree by callings their setState method, which indicates that some of their internal state has changed in a way that might impact the user interface in this subtree.
此刻,State对象被完全初始化并且框架层可能多次调用build函数构建子widget来呈现用户界面,请求调用State函数setState来重写构建子widget,由此表明构成界面的子widget内部发生变化能够影响整个界面的变化。
当导航到第二个page时:
I/flutter ( ......): BaseWidgetState__NextPageWidgetState_initState
I/flutter ( ......): BaseWidgetState__NextPageWidgetState_didChangeDependencies
I/flutter ( ......): BaseWidgetState__NextPageWidgetState_build
I/flutter ( ......): BaseWidgetState__HomePageWidgetState_deactivate
I/flutter ( ......): BaseWidgetState__HomePageWidgetState_build
.deactivate
If the subtree containing the State object is removed from the tree (e.g., because the parent built a widget with a different runtimeType or Widget.key), the framework calls the deactivate method. Subclasses should override this method to clean up any links between this object and other elements in the tree (e.g. if you have provided an ancestor with a pointer to a descendant's RenderObject).
如果视图集合中删除子视图(因为父视图由一个个不同runTimetype或key创建的子视图构建),框架层会调用deactivate函数。State子类应该重写该函数来清除此对象与树中的其他元素之间的任何关联(如果你为此对象提供了指向其他元素 RenderObject的指针)
返回到第一个page时:
I/flutter ( 7347): BaseWidgetState__HomePageWidgetState_deactivate
I/flutter ( 7347): BaseWidgetState__HomePageWidgetState_build
I/flutter ( 7347): BaseWidgetState__NextPageWidgetState_deactivate
I/flutter ( 7347): BaseWidgetState__NextPageWidgetState_dispose
. dispose
At this point, the framework might reinsert this subtree into another part of the tree. If that happens, the framework will ensure that it calls build to give the State object a chance to adapt to its new location in the tree. If the framework does reinsert this subtree, it will do so before the end of the animation frame in which the subtree was removed from the tree. For this reason, State objects can defer releasing most resources until the framework calls their dispose method.
此时此刻,框架层可能重新插入子视图到另外区域的视图中。如果发生这种情况,框架层将会调用build,State对象的子视图能够适应父视图新的位置。如果框架层确实插入了子视图,它将在动画帧结束之前重新插入,在动画帧中子树被从树中移除。因此,State对象可以推迟释放大部分资源,直到框架调用dispose函数。
If the framework does not reinsert this subtree by the end of the current animation frame, the framework will call dispose, which indicates that this State object will never build again. Subclasses should override this method to release any resources retained by this object (e.g., stop any active animations).
如果框架层在当前动画帧结束之前没有重新插入这个子树,那么框架将调用dispose函数,这表明这个状态对象将永远不再构建。子类应该覆盖这个方法来释放这个对象保留的任何资源(例如,停止任何活动的动画)。
After the framework calls dispose, the State object is considered unmounted and the mounted property is false. It is an error to call setState at this point. This stage of the lifecycle is terminal: there is no way to remount a State object that has been disposed.
框架层调用dispose函数后,当前State对象被视为不在挂载了,并且挂载的属性值为false。此刻调用setState是个错误,生命周期的这个阶段是终端:无法重新加载已经释放的State对象。
总结大概意思就是:框架层将要执行销毁函数时,若插入了widget到视图树种那么State对象释放会推迟同时会执行build函数;若没有插入widget到视图树中,框架层很快调用dispose函数,执行资源释放。
基类:
import 'package:flutter/material.dart';
abstract class BaseWidget extends StatefulWidget {
@override
BaseWidgetState createState() {
return getState();
}
BaseWidgetState getState();
}
abstract class BaseWidgetState<T extends BaseWidget> extends State<T> {
String curPage;
String tag = "BaseWidgetState_";
@override
void initState() {
super.initState();
onCreate();
tag = tag + curPage+"_";
print(tag + "initState\n");
}
@override
void didChangeDependencies() {
print(tag + "didChangeDependencies\n");
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
print(tag + "build\n");
return Scaffold(
body: baseBuild(context),
);
}
@override
void didUpdateWidget(T oldWidget) {
print(tag + "didUpdateWidget\n");
super.didUpdateWidget(oldWidget);
}
@override
void reassemble() {
print(tag + "reassemble\n");
super.reassemble();
}
@override
void deactivate() {
print(tag + "deactivate\n");
super.deactivate();
}
@override
void dispose() {
print(tag + "dispose\n");
onDes();
super.dispose();
}
void onCreate() {}
baseBuild(BuildContext context) {}
void onDes() {}
}
Page1:
class HomePage extends BaseWidget {
@override
BaseWidgetState<BaseWidget> getState() {
return _HomePageWidgetState();
}
}
class _HomePageWidgetState<T> extends BaseWidgetState<HomePage> {
@override
void onCreate() {
super.onCreate();
curPage = "_HomePageWidgetState";
}
@override
baseBuild(BuildContext context) {
// TODO: implement baseBuild
//return super.baseBuild(context);
return Center(
child: Container(
margin: EdgeInsets.only(top: 200.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text("首页"),
GestureDetector(
onTap: () async {
Navigator.push(context,
new MaterialPageRoute(builder: (BuildContext context) {
return new NextPage();
}));
},
child: Padding(
padding: EdgeInsets.all(10.0),
child: Text(
"\n跳转下一页",
style: TextStyle(backgroundColor: Colors.blue),
),
),
)
],
),
),
);
}
}
Page2:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_base_widget/base_widget.dart';
import 'package:flutter_base_widget/view/three_page.dart';
class NextPage extends BaseWidget {
@override
BaseWidgetState<BaseWidget> getState() {
// TODO: implement getState
return _NextPageWidgetState();
}
}
class _NextPageWidgetState<T> extends BaseWidgetState<NextPage> {
@override
void onCreate() {
super.onCreate();
curPage = "_NextPageWidgetState";
}
@override
baseBuild(BuildContext context) {
return Center(
child: Container(
margin: EdgeInsets.only(top: 200.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text("第二页"),
GestureDetector(
onTap: () async {
Navigator.pop(context);
},
child: Padding(
padding: EdgeInsets.all(10.0),
child: Text(
"\n返回上一页",
style: TextStyle(backgroundColor: Colors.blue),
),
),
),
],
),
),
);
}
}
总结:
观察State生命周期合理创建并释放资源,提升app性能。State对象从初始化、显示到销毁,生命周期每个函数充当的角色不一样,不是任何时候每个函数都需要重写,根据实际情况进行使用。
参考:
State:https://api.flutter.dev/flutter/widgets/State-class.html