从相亲来看 Flutter 的 StatefulWidget 和 StatelessWidget
楔子
雷思是一名程序员,年龄老大不小了,家里急啊,老催他相亲。可是雷思同学对相亲不太上心,相亲网站应付似的填了点东西,然后截个图给他老娘发过去,说是已经在相亲网站挂出去了。其实他压根就没当回事——程序员嘛,哪里会缺对象,现在用了 Dart 语言,连 new 都不需要了。这一天,雷思正在找 bug,刚好定位到一个对象的内存分配问题,正准备动手改呢,叮咚,手机弹了一个消息:“雷思,你好,小芙给你发送了一个见面邀请,是否接受?”雷思正准备划掉消息,瞥了一眼头像,突然有点心动,点了个“接受”按钮。于是,雷思开始了他的第一次网上相亲之旅。
相亲的准备
小芙十分注重个人形象,而且又十分善于掩藏自己的内心状态。从表面看她和普通的女孩子一样,但是内心戏却很足。
相反,程序员雷思很简单,标准的单纯技术男。
约定好的相亲时间还有三个小时,小芙就开始梳妆打扮起来,这雷思可是她从好多简历里挑出来的,必须精心准备。她始终记得妈妈教导过——女人面对男人时得优雅一点。
这个时候呢,雷思还在写代码。
相亲的开场白
相亲时间到了,雷思秉承着从国外名著学到的绅士习惯,提前了 15 分钟达到了约定的餐厅——这地点是相亲网站给他们推荐的。餐厅看着挺不错,估计消费不低。这肯定是相亲网站的合作餐厅,估计能给他们返不少点——雷思的互联网平台思维下意识就上来了。而小芙呢,自然是要等雷思到了之后才会出现。
“你好!不好意思,让你久等了!”小芙面带微笑优雅地挥手向雷思打招呼。雷思没感觉到她的不好意思,只是突然有些局促,“你……你好!呃,没事,我也才到一会。”小芙心里飘过三个字——没经验,当然,这些雷思看不出来。
相亲的过程
见了面了,招呼也打了,开始点菜吧。“你来点吧!”雷思继续遵循他的绅士风度,女士优先嘛!“你来吧,我也不懂吃些什么。”小芙自然礼貌性地推托一下。“呃,好吧!你喜欢吃什么?”“随便吧,我对吃没什么特别讲究。”“那我就随便点了啊。”雷思没有注意到小芙的表情表了,真的随便点了两个菜。
接下来的过程就有点无聊了,结果自然是吃完各回各家。
结局
“相亲也就这样吧。”雷思没多想,回家洗个澡,翻了会掘金的沸点——这个比相亲有趣多了!而小芙回到家,失望之情依然没有消散。她想不明白怎么就一时脑热要决定和这个叫雷思的人相亲,程序员真的像外界传言的那样无趣(简单)!过了相当一会,才平复自己的懊恼的情绪。
正当小芙准备将雷思从关注列表删除时,她突然想明白了当时为什么会决定和雷思相亲,应该是这个名字和她喜欢的蕾丝
一样的读音吧。她点了一下“取消关注”,就这样,雷思从她的关注列表中消失了。
后记
从雷思和小芙的相亲故事可以看到,雷思(StatelessWidget)作为无状态组件,真的很简单。而小芙(StatefulWidget)作为有状态组件,内心戏十足。我们以一个演示页面为例。
首次进入该页面时,打印出来的内容如下,可以看到小芙多了 2 个步骤,分别是initState
和didChangeDependencies
。也就是有状态组件会多经历两个步骤:
initState
:初始化状态,在对象插入到组件树后调用。而在组件的状态创建和初始化状态之间,框架会给状态绑定一个BuildContext
。通常我们会在这里请求网络或其他界面所需要的数据。didChangeDependencies
:当状态依赖的对象改变的时候被调用(例如一个InheritedWidget
被改变时),当initState
完成后(即初始化完成后)会马上调用该方法。该方法调用后会调用build
重新构建组件树。因为每次状态依赖改变时都会调用build
方法,因此通常不需要子类重载该方法,除非是有些负荷过重的任务(如单次的网络请求)不想每次build
时调用。
之后就是 build
方法了,这个在无状态和有状态组件都有。在有状态组件中,当初始化完成或调用setState
如小芙的表情改变)会进行调用。
对于无状态组件,后面就没有别的方法了,但是对于有状态组件还存在四个方法:
reassemble
:重装时调用,这个一般是在热重载的时候(我们修改完代码,直接保存后界面会随之更新)。热重载会重新构建组件,但不会初始化状态。只是会在构建完成后调用didUpdateWidget
,告知组件更新完成。didUpdateWidget
:当组件配置更改时调用。父组件重建时会调用树中的有状态的子组件的该方法。同时会显示一个新的同类型组件和 key。框架会更新组件的状态指向新的组件,然后调用该方法,并把旧组件传递给该方法。该方法调用后总是会调用 build 方法。通常在该方法中完成组件移除的动作,例如动画。
deactivate
:组件从组件树移除时会被调用,当然有时候组件被移除后可能被重新插入到组件的别的位置,这时候会调用 build 方法重新构建组件树。如果完全从组件树移除,之后就会调用dispose
销毁组件。在该方法中可以解除大部分对象的引用,从而释放资源,直到dispose
调用后释放所有资源。dispose
:当有状态组件再也不会调用 build 时调用该方法(通常是退出页面),在这里可以消除一些引用对象(如定时器,尚未结束的动画)来释放资源。下图展示了有状态组件的状态切换过程。
从有状态和无状态组件的对比来看,有状态组件要维护的生命周期函数多好几个,性能上自然会消耗更多资源,因此如果没有必要,推荐尽量使用无状态组件。
版权声明: 本文为 InfoQ 作者【岛上码农】的原创文章。
原文链接:【http://xie.infoq.cn/article/0187a552e5acad12afd85edba】。文章转载请联系作者。
评论