当前位置: 首页 > news >正文

深入理解Flutter生命周期函数之StatefulWidget(一)

目录

前言

1.为什么需要生命周期函数

2.开发过程中常用的生命周期函数

1.initState() 

2.didChangeDependencies()

3.build()

4.didUpdateWidget()

5.setState() 

6.deactivate()

7.dispose()

3.Flutter生命周期总结

1.调用顺序

2.函数调用时机以及主要作用

4.生命周期函数的验证

1.创建和销毁时期函数的验证

2.didUpdateWidget函数验证

3.didChangeDependencies函数验证


前言

        在Flutter中,生命周期函数是管理StatefulWidget状态的关键机制。通过生命周期函数,我们可以控制Widget的初始化、更新和销毁过程,使得应用的状态管理和资源控制更加灵活。本文将详细介绍Flutter中的生命周期函数,帮助你更好地掌握Flutter应用的生命周期。

1.为什么需要生命周期函数

        生命周期函数允许我们在Widget的创建、更新和销毁过程中执行特定操作,比如数据的初始化、网络请求、资源的释放等。尤其是在StatefulWidget中,这些函数确保了应用在不同状态下的正确行为。

2.开发过程中常用的生命周期函数

1.initState() 

        这个方法在State对象被插入到树中时调用,仅调用一次。

        适合做初始化操作,例如初始化变量、加载数据或创建动画控制器。

@override
void initState() {super.initState();debugPrint("initState method is called!");
}

2.didChangeDependencies()

        这个方法在initState()调用之后,或者当依赖的InheritedWidget发生变化时调用。

        这个方法适用于需要访问依赖于上下文的情况,比如当Widget依赖于某个InheritedWidget的变化。

        下面的代用于打印"didChangeDependencies method is called!"。

@override
void didChangeDependencies() {super.didChangeDependencies();debugPrint("didChangeDependencies method is called!");
}

3.build()

        build函数是构建UI的核心函数。

        build()在每次Widget需要重建时都会调用,包括在初次加载时、调用setState()之后。

        build方法用于描述Widget在屏幕上的展示方式。这个函数会频繁调用,因此确保代码尽量简洁高效。

        在这段代码中,build()函数返回一个带有计数器的页面,并包含一个按钮用于增加计数器。

@override
Widget build(BuildContext context) {debugPrint("build method is called!");return Scaffold(appBar: AppBar(backgroundColor: Theme.of(context).colorScheme.inversePrimary,title: Text(widget.title),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[const Text('You have pushed the button this many times:',),Text('$_counter',style: Theme.of(context).textTheme.headlineMedium,),ElevatedButton(onPressed: (){// 跳转逻辑}, child: const Text('跳转下一个页面')),],),),floatingActionButton: FloatingActionButton(onPressed: _incrementCounter,tooltip: 'Increment',child: const Icon(Icons.add),),);
}

4.didUpdateWidget()

        调用时机:当父Widget重新构建,并将新的Widget传递给子Widget时调用。

        作用:适合在父Widget属性变化时执行相应操作,比如更新状态或重新初始化数据。

        在下面代码中,它打印"didUpdateWidget method is called!",用于展示父级属性更新时的情况。

@override
void didUpdateWidget(covariant MyHomePage oldWidget) {super.didUpdateWidget(oldWidget);debugPrint("didUpdateWidget method is called!");
}

5.setState() 

        调用时机:在状态变化时,通过手动调用setState()来触发。

        作用:通知Flutter框架状态已改变,触发build()方法重新构建Widget。注意避免频繁调用setState()以减少性能开销。

@override
void didUpdateWidget(covariant MyHomePage oldWidget) {super.didUpdateWidget(oldWidget);debugPrint("didUpdateWidget method is called!");
}

6.deactivate()

        调用时机:当State对象被临时从树中移除时调用。

       作用:可以在这里执行一些临时清理工作。通常不需要在这里执行大量操作,使用场景不多。

        在这段代码中,deactivate()打印了"deactivate method is called!"。

@override
void deactivate() {super.deactivate();debugPrint("deactivate method is called!");
}

7.dispose()

        调用时机:当State对象永久性地从树中移除时调用。

        作用:适合释放资源,比如取消订阅、关闭控制器等。
        在代码中,dispose()打印了"dispose method is called!",用来展示页面被销毁时的情况。

@override
void dispose() {super.dispose();debugPrint("dispose method is called!");
}

3.Flutter生命周期总结

1.调用顺序

        通过上面的介绍,可以看到StatefulWidget的生命周期有以下顺序:

  1. 创建阶段:initState() → didChangeDependencies()
  2. 更新阶段:build() → didUpdateWidget() → setState()
  3. 销毁阶段:deactivate() → dispose()

       每个函数在Widget生命周期中扮演着不同的角色:

2.函数调用时机以及主要作用

函数

调用时机主要作用

initState()

Widget被插入树中时调用一次

初始化操作,仅调用一次

didChangeDependencies()

initState()后及依赖变化时调用

处理依赖项

build()

每次Widget需要重建时

构建UI并返回Widget

didUpdateWidget()

父Widget重新构建并传入新参数时调用

处理父组件属性变化

setState()

状态变化时手动调用

更新Widget并触发重建

deactivate()

State从树中暂时移除时

清理临时状态(不常用)

dispose()

State永久移除时

释放资源,避免内存泄漏

4.生命周期函数的验证

1.创建和销毁时期函数的验证

        我们以下面的代码为例,当app启动的之后:

        图1.示例demo

     控制台打印信息如下:

图2.进入页面控制台打印日志

        当我们点击remove按钮之后,移除子控件,控制台的打印信息如下:

图3.点击Remove之后控制台打印日志

2.didUpdateWidget函数验证

        要确保 didUpdateWidget 函数被调用,需要使 StatefulWidget 的 父级组件对其属性进行更新,而不是使用 UniqueKey 强制组件重新创建。我们修改下代码,点击按钮之后,修改子组件的颜色,通过更新 ChildWidget 的 color 属性触发 didUpdateWidget 的调用。     

        效果图如下:   

       图4.didUpdateWidge函数验证demo
        然后我们在didUpdateWidge中打印该函数,点击按钮之后,控制台打印信息如下:

图5.控制台打印日志

        完整代码如下:

import 'package:flutter/material.dart';class LifecycleDemoApp extends StatelessWidget {const LifecycleDemoApp({super.key});@overrideWidget build(BuildContext context) {return MaterialApp(home: const ParentPage(),);}
}class ParentPage extends StatefulWidget {const ParentPage({super.key});@overrideState<ParentPage> createState() => _ParentPageState();
}class _ParentPageState extends State<ParentPage> {Color childColor = Colors.blue;@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Lifecycle Demo')),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [ElevatedButton(onPressed: () {setState(() {// Toggle color between blue and greenchildColor = childColor == Colors.blue ? Colors.green : Colors.blue;});},child: const Text('Change Child Widget Color'),),const SizedBox(height: 20),ChildWidget(color: childColor, // Pass updated color),],),));}
}class ChildWidget extends StatefulWidget {final Color color;const ChildWidget({super.key, required this.color});@overrideState<ChildWidget> createState() => _ChildWidgetState();
}class _ChildWidgetState extends State<ChildWidget> {@overridevoid initState() {super.initState();debugPrint("ChildWidget: initState");}@overridevoid didChangeDependencies() {super.didChangeDependencies();debugPrint("ChildWidget: didChangeDependencies");}@overridevoid didUpdateWidget(covariant ChildWidget oldWidget) {super.didUpdateWidget(oldWidget);debugPrint("ChildWidget: didUpdateWidget - Old color: ${oldWidget.color}, New color: ${widget.color}");}@overrideWidget build(BuildContext context) {debugPrint("ChildWidget: build");return Container(height: 100,width: 100,color: widget.color,);}@overridevoid deactivate() {super.deactivate();debugPrint("ChildWidget: deactivate");}@overridevoid dispose() {super.dispose();debugPrint("ChildWidget: dispose");}
}

3.didChangeDependencies函数验证

        要验证 didChangeDependencies 的调用时机,我们需要引入一个可以触发依赖改变的机制,比如 InheritedWidget 或 MediaQuery 的更新。以下是代码的更新版本,通过使用 InheritedWidget 来测试 didChangeDependencies 的调用。

        我们修改下代码:

import 'package:flutter/material.dart';void main() {runApp(const LifecycleDemoApp());
}class LifecycleDemoApp extends StatelessWidget {const LifecycleDemoApp({super.key});@overrideWidget build(BuildContext context) {return InheritedColorProvider(color: Colors.blue,child: MaterialApp(home: const ParentPage(),),);}
}class InheritedColorProvider extends InheritedWidget {final Color color;const InheritedColorProvider({super.key,required this.color,required Widget child,}) : super(child: child);static InheritedColorProvider? of(BuildContext context) {return context.dependOnInheritedWidgetOfExactType<InheritedColorProvider>();}@overridebool updateShouldNotify(InheritedColorProvider oldWidget) {return color != oldWidget.color;}
}class ParentPage extends StatefulWidget {const ParentPage({super.key});@overrideState<ParentPage> createState() => _ParentPageState();
}class _ParentPageState extends State<ParentPage> {Color appColor = Colors.blue;void _changeColor() {setState(() {appColor = appColor == Colors.blue ? Colors.green : Colors.blue;});}@overrideWidget build(BuildContext context) {return InheritedColorProvider(color: appColor,child: Scaffold(appBar: AppBar(title: const Text('Lifecycle Demo'),),body: Column(mainAxisAlignment: MainAxisAlignment.center,children: [ElevatedButton(onPressed: _changeColor,child: const Text('Change Inherited Color'),),const SizedBox(height: 20),const ChildWidget(),],),),);}
}class ChildWidget extends StatefulWidget {const ChildWidget({super.key});@overrideState<ChildWidget> createState() => _ChildWidgetState();
}class _ChildWidgetState extends State<ChildWidget> {@overridevoid initState() {super.initState();debugPrint("ChildWidget: initState");}@overridevoid didChangeDependencies() {super.didChangeDependencies();debugPrint("ChildWidget: didChangeDependencies - Color: ${InheritedColorProvider.of(context)?.color}");}@overrideWidget build(BuildContext context) {debugPrint("ChildWidget: build");final color = InheritedColorProvider.of(context)?.color ?? Colors.transparent;return Container(height: 100,width: 100,color: color,);}@overridevoid didUpdateWidget(covariant ChildWidget oldWidget) {super.didUpdateWidget(oldWidget);debugPrint("ChildWidget: didUpdateWidget");}@overridevoid deactivate() {super.deactivate();debugPrint("ChildWidget: deactivate");}@overridevoid dispose() {super.dispose();debugPrint("ChildWidget: dispose");}
}

        在修改之后的代码中,我们做了以下工作:

1.引入了InheritedWidget

        InheritedColorProvider 是一个简单的 InheritedWidget,用来共享 color 属性。

 2.修改了更新逻辑

        在 ParentPage 中,通过修改 InheritedColorProvider 的 color 属性触发 didChangeDependencies。

3.验证依赖关系

        子组件 ChildWidget 会依赖 InheritedColorProvider,当 color 发生变化时,didChangeDependencies 会被调用。

        当我们点击修改按钮之后,控制台打印日志如下:

ChildWidget: initState
ChildWidget: didChangeDependencies - Color: Color(0xff0000ff)
ChildWidget: build
ChildWidget: didChangeDependencies - Color: Color(0xff00ff00)
ChildWidget: build

相关文章:

深入理解Flutter生命周期函数之StatefulWidget(一)

目录 前言 1.为什么需要生命周期函数 2.开发过程中常用的生命周期函数 1.initState() 2.didChangeDependencies() 3.build() 4.didUpdateWidget() 5.setState() 6.deactivate() 7.dispose() 3.Flutter生命周期总结 1.调用顺序 2.函数调用时机以及主要作用 4.生…...

413: Quick Sort

解法&#xff1a; #include <bits/stdc.h> using namespace std; const int N1e55; int a[N]; int n;int main(int argc, char** argv) {cin>>n;for (int i0;i<n;i) cin>>a[i];sort(a,an);for (int i0;i<n;i) cout<<a[i]<<" "…...

vue之axios根据某个接口创建实例,并设置headers和超时时间,捕捉异常

import axiosNew from axios;//给axios起个别名//创建常量实例 const instanceNew axiosNew.create({//axios中请求配置有baseURL选项&#xff0c;表示请求URL的公共部分&#xff0c;url baseUrl requestUrlbaseURL: baseURL,//设置超时时间为20秒timeout: 20000,headers: {…...

Pandas数据透视表:交叉分析与聚合计算

大家好&#xff0c;在数据分析中&#xff0c;数据透视表&#xff08;Pivot Table&#xff09;是一种强大的工具&#xff0c;用于交叉分析和聚合计算。Pandas库中的数据透视表功能&#xff0c;使我们能够在多维数据中快速生成汇总表、统计特定维度的聚合数据&#xff0c;帮助揭示…...

软件设计师考试大纲

文章目录 一 、考 试 说 明1. 考试目标2. 考试要求3. 考试科目设置 二、考 试 范 围考试科目1:计算机与软件工程知识1. 计算机系统基础知识1.1计算机内数据的表示及运算1.2 其他数学基础知识1.3 计算机硬件基础知识1.3.1 计算机系统的组成、体系结构分类及特性1.3.2 存储系统1.…...

一文说清C++类型转换操作符(cast operator)

一 前言 大家在编程时&#xff0c;一定会遇到要做类型转换的应用场景。 但是&#xff0c;C风格的类型转换太强大&#xff0c;太危险&#xff0c;它允许将一个给定类型转换成我们想要的任何其他类型。 所以在C中&#xff0c;提供了一些更安全和更明确的类型转换操作符&#xff…...

MOSFET电路栅源极GS之间并联电容后,MOS炸管原因分析

1、前言 在介绍&#xff0c;在进行MOSFET相关的电路设计时&#xff0c;可能会遇到MOSFET误导通的问题&#xff0c;为了解决此问题&#xff0c;我们提出了两种方法&#xff0c;一种是增大MOSFET栅极串联电阻的阻值&#xff0c;另外一种是在MOSFET栅-源极之间并联一个电容&#…...

gitHub常用操作

gitHub常用操作 1、把项目拉下来2、添加上游仓库3、进入分支4、从上游仓库拉取更新 1、把项目拉下来 在对应项目的右上角点击fork&#xff0c;fork下来&#xff1a;将远程仓库复制到个人仓库 在创建好的分支文件夹下使用 git clone自己远程仓库下的http地址&#xff08;fork…...

[项目代码] YOLOv5 铁路工人安全帽安全背心识别 [目标检测]

YOLOv5是一种单阶段&#xff08;one-stage&#xff09;检测算法&#xff0c;它将目标检测问题转化为一个回归问题&#xff0c;能够在一次前向传播过程中同时完成目标的分类和定位任务。相较于两阶段检测算法&#xff08;如Faster R-CNN&#xff09;&#xff0c;YOLOv5具有更高的…...

Java 垃圾回收机制(GC)概览

简介 Java垃圾收集、堆和运行时编译器默认选择 jdk1.9开始&#xff0c;默认使用G1收集器&#xff0c;GC Threads的最大数量受堆大小和可用CPU资源限制初始堆大小为物理内存的1/64最大堆大小为物理内存的1/4分层编译器&#xff0c;同时使用C1和C2 JVM 垃圾收集器可以为配置优…...

Kafka节点服役和退役

1 服役新节点 1&#xff09;新节点准备 &#xff08;1&#xff09;关闭 bigdata03&#xff0c;进行一个快照&#xff0c;并右键执行克隆操作。 &#xff08;2&#xff09;开启 bigdata04&#xff0c;并修改 IP 地址。 vi /etc/sysconfig/network-scripts/ifcfg-ens33修改完…...

Git如何简单使用

文章目录 GitGitlabGitLab和GitHub有什么区别?Gitlab简单使用Gitlab常用指令Git Git是一个分布式版本控制系统。 它用于记录文件的修改历史,方便多人协作开发软件等项目。例如一个软件开发团队,成员们会频繁修改代码,Git可以追踪每个人的修改内容、时间等信息。 主要功能…...

酒水分销积分商城小程序开发方案php+uniapp

酒水分销积分商城小程序开发&#xff0c;开发语言后端php&#xff0c;前端uniapp。核心功能模块&#xff1a;酒水商城、积分商城、二级分销、抽奖、优惠券。可以二开或定制。协助部署搭建。...

MTU-内核态(数据链路层或网络接口上能够传输的最大数据包大小)

MTU&#xff08;最大传输单元&#xff0c;Maximum Transmission Unit&#xff09;是网络中用于表示数据链路层或网络接口上能够传输的最大数据包大小。 1. 工作原理 MTU 决定了一个数据包&#xff08;包括头部和数据部分&#xff09;的最大长度。它影响到数据的传输&#xff…...

React的基础API介绍(一)

目录 useEffect1. 替代生命周期方法2. 副作用管理3. 依赖项数组4. 多次使用5. 与闭包配合6. 支持异步操作7. 减少样板代码 注意事项useEffetct是如何拿到变量count最新的值&#xff1f;1. 每次渲染都会创建新的函数作用域2. 闭包捕获最新的状态值3. useEffect 的执行时机 useLa…...

【Electron】总结:如何创建Electron+Element Plus的项目

我将结合官网手册与AI问到的信息&#xff0c;直接给出步骤&#xff0c;与命令。 一、准备环境 首先在C盘Users&#xff0c;你的登录的账号名文件夹下&#xff0c;编辑.npmrc文件。添加镜像地址。 如果使用了yarn&#xff0c;则是.yarnrc。可以全部都配置。 npm install -g …...

从依托指标字典到 NoETL 自动化指标平台,指标口径一致性管理的进阶

今天&#xff0c;我们一起来梳理和盘点下不同代际指标平台如何实现指标口径一致性管理&#xff1a; 第一代&#xff1a;指标口径登记与管理 第一代指标平台聚焦于指标口径的登记与管理&#xff0c;依托指标字典实现企业指标口径的有效检索与管理功能。 此阶段&#xff0c;业…...

嵌入式面试题练习 - 2024/11/15

欢迎找我进行职业规划&#xff0c;超值的自我投资 -> 嵌入式软件工程师一对一指导 1.设有定义char *p[]{"Shanghai","Beijing","Honkong"};则结果为j字符的表达式是&#xff08;&#xff09; A *p[1] 3 B *(p[1] 3) C *(p[3] 1) D p[3] […...

分析http话术异常挂断原因

用户反馈在与机器人通话时&#xff0c;自己明明有说话&#xff0c;但是通话还是被挂断了&#xff0c;想知道原因。 分析日志 我们根据用户提供的freeswitch日志分析&#xff1a;发现是因为超时导致话术执行hangup动作&#xff0c;结束了通话。 从这一行向上分析日志&#xff…...

云岚到家 秒杀抢购

目录 秒杀抢购业务特点 常用技术方案 抢券 抢券界面 进行抢券 我的优惠券列表 活动查询 系统设计 活动查询分析 活动查询界面显示了哪些数据&#xff1f; 面向高并发如何提高活动查询性能&#xff1f; 如何保证缓存一致性&#xff1f; 数据流 Redis数据结构设计 如…...

JavaSec-RCE

简介 RCE(Remote Code Execution)&#xff0c;可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景&#xff1a;Groovy代码注入 Groovy是一种基于JVM的动态语言&#xff0c;语法简洁&#xff0c;支持闭包、动态类型和Java互操作性&#xff0c…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:

根据万维钢精英日课6的内容&#xff0c;使用AI&#xff08;2025&#xff09;可以参考以下方法&#xff1a; 四个洞见 模型已经比人聪明&#xff1a;以ChatGPT o3为代表的AI非常强大&#xff0c;能运用高级理论解释道理、引用最新学术论文&#xff0c;生成对顶尖科学家都有用的…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

WEB3全栈开发——面试专业技能点P7前端与链上集成

一、Next.js技术栈 ✅ 概念介绍 Next.js 是一个基于 React 的 服务端渲染&#xff08;SSR&#xff09;与静态网站生成&#xff08;SSG&#xff09; 框架&#xff0c;由 Vercel 开发。它简化了构建生产级 React 应用的过程&#xff0c;并内置了很多特性&#xff1a; ✅ 文件系…...

【实施指南】Android客户端HTTPS双向认证实施指南

&#x1f510; 一、所需准备材料 证书文件&#xff08;6类核心文件&#xff09; 类型 格式 作用 Android端要求 CA根证书 .crt/.pem 验证服务器/客户端证书合法性 需预置到Android信任库 服务器证书 .crt 服务器身份证明 客户端需持有以验证服务器 客户端证书 .crt 客户端身份…...