当前位置: 首页 > 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数据结构设计 如…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命

在华东塑料包装行业面临限塑令深度调整的背景下&#xff0c;江苏艾立泰以一场跨国资源接力的创新实践&#xff0c;重新定义了绿色供应链的边界。 跨国回收网络&#xff1a;废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点&#xff0c;将海外废弃包装箱通过标准…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

自然语言处理——Transformer

自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效&#xff0c;它能挖掘数据中的时序信息以及语义信息&#xff0c;但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN&#xff0c;但是…...

Typeerror: cannot read properties of undefined (reading ‘XXX‘)

最近需要在离线机器上运行软件&#xff0c;所以得把软件用docker打包起来&#xff0c;大部分功能都没问题&#xff0c;出了一个奇怪的事情。同样的代码&#xff0c;在本机上用vscode可以运行起来&#xff0c;但是打包之后在docker里出现了问题。使用的是dialog组件&#xff0c;…...

【分享】推荐一些办公小工具

1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由&#xff1a;大部分的转换软件需要收费&#xff0c;要么功能不齐全&#xff0c;而开会员又用不了几次浪费钱&#xff0c;借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

群晖NAS如何在虚拟机创建飞牛NAS

套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...

Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案

在大数据时代&#xff0c;海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构&#xff0c;在处理大规模数据抓取任务时展现出强大的能力。然而&#xff0c;随着业务规模的不断扩大和数据抓取需求的日益复杂&#xff0c;传统…...