首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Flutter 生命周期详解

Flutter 生命周期详解

作者头像
子晋
发布于 2022-01-19 05:59:03
发布于 2022-01-19 05:59:03
1.4K00
代码可运行
举报
文章被收录于专栏:子晋城子晋城
运行总次数:0
代码可运行

简介

FlutterAndroid 的 Activity、iOS 的 ViewController 一样都拥有自己的生命周期。在 Flutter 中几乎所有的对象都是一个 Widget,其中 Widget 又分为 StatelessWidget(即:无状态的 Widget) 和 StatefulWidget (即:有状态的 Widget),这里所说的 Flutter 的生命周期其实就是讲 StatefulWidget 的生命周期,它存在于 framework.dart 的 State 类中。

代码实测

写个有状态类并混入 WidgetsBindingObserver 配合监听特殊状态及其一个按钮,调用 setState, 给生命周期的方法新增打印:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: '生命周期',
      home: new LiftCycle(),
    );
  }
}

class LiftCycle extends StatefulWidget {
  @override
  _LiftCycleState createState() => _LiftCycleState();
}

class _LiftCycleState extends State<LiftCycle> with WidgetsBindingObserver {
  int count = 0;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    print('初始化 initState');
  }

  @override
  void didUpdateWidget(LiftCycle oldWidget) {
    super.didUpdateWidget(oldWidget);
    print('组件更新 didUpdateWidget');
  }

  @override
  void reassemble() {
    super.reassemble();
    print('重新安装 reassemble');
  }

  @override
  void deactivate() {
    super.deactivate();
    print('停用  deactivate');
  }

  @override
  void dispose() {
    super.dispose();
    WidgetsBinding.instance.removeObserver(this);
    print('销毁 dispose');
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    print('特殊状态 state:$state');
  }

  @override
  void setState(fn) {
    super.setState(fn);
    print('状态刷新 setState');
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(title: new Text('生命周期')),
      body: new Center(
        child: new FlatButton(
          onPressed: () => setState(() => count++),
          child: new Text('$count'),
        ),
      ),
    );
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    print('依赖改变 didChangeDependencies');
  }
}

然后我们现在来看看打印流程,正常打开 App 什么都不操作,就打印了:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
I/flutter (15867): 初始化 initState
I/flutter (15867): 依赖改变 didChangeDependencies
I/flutter (15867): 重新安装 reassemble
I/flutter (15867): 组件更新 didUpdateWidget

热重载打印:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
I/flutter (16141): 重新安装 reassemble
I/flutter (16141): 组件更新 didUpdateWidget
Reloaded 0 of 468 libraries in 186ms.

点击按钮打印:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
I/flutter (16141): 状态刷新 setState
// count也+1了,说明重新调用过build。

流程图

构造函数:

构造函数不属于生命周期,必然是要第一个调用的,也就是调用前 State 的 widget 属性为空。

initState 初始化:

当此对象插入树中时调用,框架会调用一次此方法并不会再次重复执行, 如果 State 的 build 方法依赖于本身可以更改状态的对象,例如:ChangeNotifier 或 Stream, 或者某些其他可以订阅的对象接收通知,可以在此方法订阅,但记得去 dispose 取消订阅。

didChangeDependencies 依赖改变:

顾名思义,依赖项更改时调用,但也会在 initState 之后调用, 在这个方法调用 BuildContext.inheritFromWidgetOfExactType 是安全的。

build 构建:

会在以下场景调用:

  • initState() 之后。
  • didUpdateWidget() 之后。
  • setState() 之后。
  • didChangeDependencies() 之后。
  • State 对象从树中一个位置移除后会调用 deactivate,然后又重新插入到树的其它位置之后。

reassemble 重新安装:

专门为了开发调试而提供的,在热重载 hot reload 时会被调用,此回调在 Release 模式下永远不会被调用。

didUpdateWidget 组件更新:

当组件的状态改变的时候就会调用 didUpdateWidget(),比如调用了 setState(), 在 widget 重新构建时,Flutter framework 会调用 Widget.canUpdate 来检测 Widget 树中同一位置的新旧节点, 然后决定是否需要更新,如果 Widget.canUpdate 返回 true 则会调用此回调。正如之前所述,Widget.canUpdate 会在 新旧 widget 的 key 和 runtimeType 同时相等时会返回 true,也就是说在新旧 widget 的 key 和 runtimeType 同时相等时 didUpdateWidget() 就会被调用。

deactivate 暂停:

State 对象从树中被移除时(在 dispose 之前),会调用这个函数来将对象暂停。

dispose 销毁:

当 State 对象被销毁时调用,通常在此回调中释放资源和移除监听。

特殊状态

我们自定义的 State 类混入了 WidgetsBindingObserver,所以可以使用他的暂停和恢复。

初始化:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@override
void initState() {
  super.initState();
  WidgetsBinding.instance.addObserver(this); // 在这初始化了
  print('初始化 initState');
}

销毁:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@override
void dispose() {
  super.dispose();
  WidgetsBinding.instance.removeObserver(this); // 在这销毁
  print('销毁 dispose');
}

使用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
  super.didChangeAppLifecycleState(state);
  print('特殊状态 state:$state');
}

这个 didChangeAppLifecycleState 是 WidgetsBindingObserver 类的一个方法,可以用来判断当前的状态是在前台还是后台。

这个方法接收一个AppLifecycleState类型的枚举:

枚举值

含义

resumed

程序可见,并响应用户输入。

inactive

处于非活动状态,未收到用户输入。

paused

程序当前不可见,不响应用户输入,并且在后台运行。

suspending

程序将暂时暂停。

AppLifecycleState 实测

当App返回到桌面或者其他不可见状态,但并未结束:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
I/flutter ( 2428): 特殊状态 state:AppLifecycleState.inactive
I/flutter ( 2428): 特殊状态 state:AppLifecycleState.paused

当App回到可见状态:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
I/flutter ( 2428): 特殊状态 state:AppLifecycleState.inactive
I/flutter ( 2428): 特殊状态 state:AppLifecycleState.resumed

流程图:

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-10-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
【算法系列02】整数二分怎么玩?
二分可简单的分为整数二分和浮点数二分。如果说二分是否一定能得出结果,除开原题出问题,绝不会有第二种情况。二分是一定能有解的,当然前提得代码正确。
小Bob来啦
2021/07/06
4660
算法基础:二分图解及代码模板
二分的本质是边界,将区间分为两个,一边满足某条性质,另一边不满足某条性质。然后可以找到这两个区间的边界,找任意一个区间的边界都可以。
timerring
2023/05/24
4870
算法基础:二分图解及代码模板
ACM/蓝桥杯基础算法篇——二分
分析:先找最左边的x,check函数为要找的整数区间,在x的右边,所以是qmid >= x, x在mid的左边,所以x所在区间为l, mid。再找最右边的x,check函数为要找的整数区间,在x的左边,所以是qmid <= x, x在mid的右边,所以x所在区间为mid, r。
战士小小白
2022/07/11
3550
ACM/蓝桥杯基础算法篇——二分
算法基础(三)| 二分图解及代码模板
二分的本质是边界,将区间分为两个,一边满足某条性质,另一边不满足某条性质。然后可以找到这两个区间的边界,找任意一个区间的边界都可以。
timerring
2022/09/27
4040
算法基础(三)| 二分图解及代码模板
基础算法---二分查找
二分查找的必要条件并不是单调,而是当我给定一个边界条件,然后左边满足这个边界条件,右边不满足这个边界条件,然后可以查找这个临界点,这就是二分查找
用户11305458
2024/10/09
1120
基础算法---二分查找
基本算法篇——二分查找
基本算法篇——二分查找 本次我们介绍基础算法中的二分查找,我们会从下面几个角度来介绍二分查找: 二分查找简述 二分查找模板 二分查找边界 例题数的范围 二分查找简述 首先我们来简单介绍一下二分查找: 二分查找就是在一个数组中快速得找到我们所需要的值 二分查找通常是在有单调性的数组中进行;有单调性的数组必定可以二分,但二分可以运行在没有单调数的数组中 然后我们来介绍二查找分的思想: 确定一个分界点 // 同样我们需要先确定一个分界点 // 我们的二分查找的分界点通常设计为(l+r)/2或者(l+r
秋落雨微凉
2022/11/14
2190
你真的懂二分吗?
二分算法,又称为二分搜索或折半搜索,是一种在有序数组中查找特定元素的搜索算法。其基本思想是将数组分成两半,然后根据目标值与中间元素的大小关系来决定是继续在左侧还是右侧进行搜索。这个过程会不断重复,直到找到目标值或搜索范围为空为止。
摆烂小白敲代码
2024/09/23
1360
你真的懂二分吗?
算法基础学习笔记——②二分
解释这里为什么要+1:如果当l=r-1时, 不加1时mid=(l+r)/2=l(要下取整,1被略掉),进行if(check(mid))如果为 true,则更新l=mid,可此时mid算出还是=l,故进入死循环) 此处check是否满足红色性质
命运之光
2024/03/20
1270
算法基础学习笔记——②二分
机器人跳跃问题 (二分)
机器人正在玩一个古老的基于DOS的游戏。 游戏中有N+1座建筑——从0到N编号,从左到右排列。 编号为0的建筑高度为0个单位,编号为 i 的建筑高度为H(i)个单位。 起初,机器人在编号为0的建筑处。 每一步,它跳到下一个(右边)建筑。 假设机器人在第k个建筑,且它现在的能量值是E,下一步它将跳到第k+1个建筑。 如果H(k+1)>E,那么机器人就失去H(k+1)-E的能量值,否则它将得到E-H(k+1)的能量值。 游戏目标是到达第N个建筑,在这个过程中能量值不能为负数个单位。 现在的问题是机器人以多少能量值开始游戏,才可以保证成功完成游戏?
dejavu1zz
2020/10/23
5020
Acwing二分和前缀和(一)
左端点的判断条件是mid>=x,因为是升序的,如果成立,说明左端点l只会在mid上或mid左侧。 将右端点调整为mid,这样mid只会不变或变小。 现在变小了,说明目前的l并非答案的左区间,中间掺杂了更小的数列,此时需要使左区间l+1。 左端点是通过l查找,l从0累加,不会产生遗漏。 左端点确定之后,右端点从n-1,也就是最右端开始,累减,确定答案的右端点。
WuShF
2024/02/17
1790
Acwing二分和前缀和(一)
【算法题解】二分查找的经典问题解析
圈出来的都是重要信息。 这道题的大致意思就是有N个小朋友,现在有K个蛋糕,这K个蛋糕,蛋糕的长和宽都给出,现在要切蛋糕,但是蛋糕必须满足一定条件,保证边长是整数,并且保证切出来的蛋糕都是一样的并且是正方形(输入的蛋糕必须保证每个小朋友都可以分到1*1的蛋糕)。
用户11305458
2024/10/18
1770
【算法题解】二分查找的经典问题解析
你必须知道的基础算法
对于贪心算法,我们要先将问题简化,然后依据贪心算法的理念,例如可以一起进行的事情,让他们一起进行。可以用一个条件完成的,就用一个条件完成。贪心算法就像人的贪心理念一样,先将可以贪的贪干净,然后在考虑特殊的情况,这样可以很好地进行代码的编写。
洋仔聊编程
2019/01/15
7880
信奥赛-刷题笔记-二分篇-T2-P1824进击的奶牛0531
https://docs.qq.com/sheet/DSmJuVXR4RUNVWWhW?tab=BB08J2
IT从业者张某某
2025/05/31
1050
信奥赛-刷题笔记-二分篇-T2-P1824进击的奶牛0531
(四)算法基础——二分算法
求下面方程的一个根:f(x) = x3 -5x2+10x-80 = 0 若求出的根是a,则要求 |f(a)| <= 10^-6
小点点
2022/12/12
5670
(四)算法基础——二分算法
【2025-02-25】基础算法:二分查找(一)
📝前言说明: ●本专栏主要记录本人的基础算法学习以及LeetCode刷题记录,主要跟随B站博主灵茶山的视频进行学习,专栏中的每一篇文章对应B站博主灵茶山的一个视频 ●题目主要为B站视频内涉及的题目以及B站视频中提到的“课后作业”。 ●文章中的理解仅为个人理解。 ●文章中的截图来源于B站博主灵茶山,如有侵权请告知。
用户11029137
2025/02/26
1220
【2025-02-25】基础算法:二分查找(一)
贪心与二分-二分答案
回顾下二分查找的思想,若序列呈升序,我们求出中间值mid,并判断是否满足条件。满足条件输出答案,若不满足将正确答案与mid进行大小的判断,如果比mid大,说明答案在右侧,更新查找区间的最小范围;如果比mid小,说明答案在左侧,更新查找区间的最大范围。
fishhh
2022/08/31
3540
贪心与二分-二分答案
快速排序、归并排序、二分算法
思路:首先随机定义数组的一个数,把他当成边界值进行排序,一般是取数组中间的一个数,在这个数的左边区间寻找一个比他大的数,在这个数的右边区间寻找一个比他小的数,将这两个数进行交换,最后左边区间的数都小于他,右边的数都大于他,然后在左右区间分别递归。
用户10604450
2024/03/15
950
信奥赛-刷题笔记-二分篇-T2-P1678烦恼的高考志愿0528
https://docs.qq.com/sheet/DSmJuVXR4RUNVWWhW?tab=BB08J2
IT从业者张某某
2025/05/28
860
信奥赛-刷题笔记-二分篇-T2-P1678烦恼的高考志愿0528
信奥赛-刷题笔记-二分篇-T2-P1918保龄球0529
https://docs.qq.com/sheet/DSmJuVXR4RUNVWWhW?tab=BB08J2
IT从业者张某某
2025/05/29
990
信奥赛-刷题笔记-二分篇-T2-P1918保龄球0529
noip2015_noip2021复赛
大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。 Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺
全栈程序员站长
2022/09/23
2360
noip2015_noip2021复赛
相关推荐
【算法系列02】整数二分怎么玩?
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档