草庐IT

Flutter 之 生命周期(三)

maskerII 2023-03-28 原文

1、Fultter 生命周期

生命周期的作用:

  • 初始化一些数据、变量、状态
  • 发送网络请求
  • 监听事件
  • 管理内存

1.1 StatelessWidget 生命周期

class MSHomePage extends StatelessWidget {
  MSHomePage() {
    print("Flutter: StatelessWidget 构造函数 调用");
  }
  @override
  Widget build(BuildContext context) {
    print("Flutter: StatelessWidget build 调用");
    return Text("Hello World");
  }
}

StatelessWidget 不可变,在它的生命周期中,只会执行构造函数、build方法

1.2 StatefulWidget 生命周期

在下图中,灰色部分的内容是Flutter内部操作的,我们并不需要手动去设置它们;
白色部分表示我们可以去监听到或者可以手动调用的方法

截屏2022-04-11 下午3.26.55.png

首先,执行StatefulWidget中相关的方法:

  • 1、执行StatefulWidget的构造函数(Constructor)来创建出StatefulWidget;

  • 2、执行StatefulWidget的createState方法,来创建一个维护StatefulWidget的State对象;

其次,调用createState创建State对象时,执行State类的相关方法:

  • 1、执行State类的构造方法(Constructor)来创建State对象;

  • 2、执行initState,我们通常会在这个方法中执行一些数据初始化的操作,或者也可能会发送网络请求;

  • 注意:这个方法是重写父类的方法,必须调用super,因为父类中会进行一些其他操作;

  • 并且如果你阅读源码,你会发现这里有一个注解(annotation):@mustCallSuper

  • 3、执行didChangeDependencies方法,这个方法在两种情况下会调用

  • 情况一:调用initState会调用;

  • 情况二:从其他对象中依赖一些数据发生改变时,比如前面我们提到的InheritedWidget(这个后面会讲到);

  • 4、Flutter执行build方法,来看一下我们当前的Widget需要渲染哪些Widget;

  • 5、当前的Widget不再使用时,会调用dispose进行销毁;

  • 6、手动调用setState方法,会根据最新的状态(数据)来重新调用build方法,构建对应的Widgets;

  • 7、执行didUpdateWidget方法是在当父Widget触发重建(rebuild)时,系统会调用didUpdateWidget方法

1.2.1 代码演示
import 'package:flutter/material.dart';

void main(List<String> args) {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  var curHomePage = MSHomePageBody();
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("声明周期"),
        ),
        body: curHomePage,
        floatingActionButton: IconButton(
          icon: Icon(Icons.change_circle),
          onPressed: () {
            setState(() {
              curHomePage = MSHomePageBody();
            });
          },
        ),
      ),
    );
  }
}

class MSHomePageBody extends StatefulWidget {
  MSHomePageBody() {
    print("1. MSHomePageBody  构造函数");
  }
  @override
  State<StatefulWidget> createState() {
    print("2. MSHomePageBody  createState");
    return _MSHomePageBodyState();
  }
}

class _MSHomePageBodyState extends State<MSHomePageBody> {
  int _counter = 0;
  _MSHomePageBodyState() {
    print("3. _MSHomePageBodyState 构造函数");
  }

  @override
  void initState() {
    print("4. _MSHomePageBodyState initState");
    super.initState();
  }

  @override
  void didChangeDependencies() {
    // 调用时机
    // 调用initState会调用
    // 从其他对象中依赖一些数据发生改变时
    print("_MSHomePageBodyState didChangeDependencies");
    super.didChangeDependencies();
  }

  @override
  void didUpdateWidget(covariant MSHomePageBody oldWidget) {
    // 调用时机
    // 当父Widget触发重建(rebuild)时,系统会调用didUpdateWidget方法
    print("_MSHomePageBodyState didUpdateWidget");
    super.didUpdateWidget(oldWidget);
  }

  @override
  Widget build(BuildContext context) {
    print("5. _MSHomePageBodyState build");
    return Column(
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        ElevatedButton(
          onPressed: () {
            setState(() {
              _counter++;
            });
          },
          child: Text(
            "点击",
            style: TextStyle(fontSize: 20),
          ),
        ),
        Text(
          "当前计数$_counter",
          style: TextStyle(fontSize: 20),
        ),
      ],
    );
  }

  @override
  void dispose() {
    print("6. Flutter: _MSHomePageBodyState dispose");
    super.dispose();
  }
}

运行App时,打印如下:

flutter: 1. MSHomePageBody  构造函数
flutter: 2. MSHomePageBody  createState
flutter: 3. _MSHomePageBodyState 构造函数
flutter: 4. _MSHomePageBodyState initState
flutter: _MSHomePageBodyState didChangeDependencies
flutter: 5. _MSHomePageBodyState build

我们手动改变counter状态(点击+按钮)时,打印如下

flutter: 5. _MSHomePageBodyState build

我们手动改变curHomePage状态(点击底部按钮)时,MSHomePageBody的父Widget发生改变,打印如下:

flutter: 1. MSHomePageBody  构造函数
flutter: _MSHomePageBodyState didUpdateWidget
flutter: 5. _MSHomePageBodyState build

1.3 生命周期的复杂版

1、mounted是State内部设置的一个属性。这个属性是在我们创建完State调用initState之前,Flutter给我们的BuildContent挂载的一个属性。这个属性最主要的作用是为了记录对应的Element是否为空


截屏2022-04-11 下午4.29.41.png

2、dirty state的含义是脏的State
它实际是通过Element的属性来标记的;
将它标记为dirty会等待下一次的重绘检查,强制调用build方法来构建我们的Widget;
3、clean state的含义是干净的State
它表示当前build出来的Widget,下一次重绘检查时不需要重新build;

有关Flutter 之 生命周期(三)的更多相关文章

  1. Flutter 环境变量配置和flutter doctor中的错误解决 - 2

    一、环境变量右键点击我的电脑-属性:然后找到环境变量 1.Android的SDK不在C盘的话需要额外配这个到用户环境变量:ANDROID_HOMED:\AndroidSDK2.然后在系统变量:Path中添加一条这样的值        D:\Flutter\flutter\bin             这个值写flutter包解压的实际地址即可 3.在系统变量中添加两个镜像变量:        变量名:FLUTTER_STORAGE_BASE_URL      变量值:https://storage.flutter-io.cn        变量名:PUB_HOSTED_URL      变量

  2. ruby - 在 Ruby 中查找周期和范围集差异的有效方法 - 2

    我在Ruby中有很多时间范围:period=Time.parse('8:00am')..Time.parse('8:00pm')incidents=[Time.parse('7:00am')..Time.parse('9:00am'),Time.parse('1:00pm')..Time.parse('3:00pm'),Time.parse('1:30pm')..Time.parse('3:30pm'),Time.parse('7:00pm')..Time.parse('9:00pm'),]我正试图在这段时间内获得一系列无事件block。对于以上内容:[Time.parse('9:00

  3. ruby-on-rails - 有没有一种简单的方法可以在 Passenger 的请求周期之外运行垃圾收集? - 2

    unicorn有OobGC可用于在一定数量的请求后运行GC.start的机架中间件。PhusionPassenger中有类似的东西吗? 最佳答案 PhusionPassenger4正式引入了带外垃圾回收机制。它比Unicorn更灵活,允许任意工作,而不仅仅是垃圾收集。http://blog.phusion.nl/2013/01/22/phusion-passenger-4-technology-preview-out-of-band-work/ 关于ruby-on-rails-有没有一种

  4. ruby-on-rails - rails 周期性任务 - 2

    我有一个ruby​​onrails应用程序,我试图在其中找到每隔几秒运行一些代码的方法。我发现了很多使用cron或类似cron的实现的信息和想法,但这些只是准确到分钟,并且/或需要外部工具。我想每15秒左右启动一次任务,并且我希望它完全独立于应用程序中(如果应用程序停止,任务也停止,并且没有外部设置)。这用于缓存数据的后台生成。每隔几秒,任务就会收集一些数据,然后将其存储在缓存中,供所有客户端请求使用。该任务非常慢,因此需要在后台运行并且不阻塞客户端请求。我是ruby​​的新手,但有很强的perl背景,我解决这个问题的方法是创建一个间隔计时器和处理程序,它fork、运行代码,然后在完成

  5. ruby-on-rails - Rails 应用程序的生命周期 - 2

    我正在尝试了解Rails应用程序的生命周期。application_controller.rb什么时候运行?是每次更改时只执行一次,还是每次请求时都执行一次?我想了解以下文件:config/environments/*.rb(开发、生产或测试,取决于当前模式)boot.rb环境.rb路线.rb我问这个的原因之一是,我想知道放在哪里比较好初始化代码自定义配置数据编辑:@Gdeglin的回答很好,但我实际上很想知道这些文件中的每一个何时运行。 最佳答案 应用程序Controller.rbApplicationController是所有C

  6. ruby - 在 Sinatra(Ruby) 中,我应该如何创建在应用程序生命周期中只赋值一次的全局变量? - 2

    在Sinatra中,我无法创建在应用程序生命周期中仅分配一次值的全局变量。我错过了什么吗?我的简化代码如下所示:require'rubygems'ifRUBY_VERSION这导致nil2在终端和,2在浏览器中。如果我尝试将@a=1放入initialize方法中,我会在WebApp.run!中遇到错误线。我觉得我错过了一些东西,因为如果我不能有全局变量,那么我如何在应用程序实例化期间加载大数据?beforedo似乎每次有来自客户端的请求时都会被调用。 最佳答案 classWebApp请注意,如果您使用Shotgun或其他在每次请求时

  7. javascript - 使用 ajax 调用 react 组件 - 生命周期 - 2

    所以我有一个使用React和Ajax调用的有趣案例。在上下文中,我有一个带有3个选项卡的Accordion。初始化Accordionreact组件后,我首先打开第一个选项卡,其余选项卡关闭。每个选项卡的主体中都有所谓的DictionaryCall组件,如下所示:returnclassDictionaryCallextendsReact.Component{constructor(props){super();this.state={word:'',data:[],error:false,nodata:false,initialLoaded:props.load}}componentDi

  8. javascript - 为什么 setInterval() 周期每次都变快? - 2

    我正在Javascript上构建自定义slider,我希望每次用户单击slider的div时,slider都应停止X秒。我的代码是:$(document).ready(function(){varciclo;varindex_slide=1;functionstartSlidercicle(){ciclo=setInterval(function(){//Slidercodegoeshere},3000);}//HereIstarttheslideranimationstartSlidercicle();//Whentheuserclicksonadivcalled'slide',st

  9. javascript - 如何从 Vue.js 中的组件生命周期方法访问 mixin 方法内部的函数 - 2

    这是一个例子:混入.jsexportdefault{methods:{aFunction(){//Somefunctionalityhere}}}组件.vueimportmixinfrom'./mixin'exportdefault{mixins:[mixin]created(){//CallaFunctiondefinedinthemixinhere}}我想从组件内部的created()生命周期方法访问在mixin方法内部定义的aFunction。 最佳答案 mixin方法与组件的当前实例合并,所以它只是:created(){th

  10. javascript - 如何知道脚本 block 或 JavaScript 代码的生命周期? - 2

    我想知道javascriptblock/函数是否在加载后始终可用。因为我已经测试了一些东西,现在我有点困惑。我将一个脚本block定义到一个div中。脚本block有一个事件处理函数,用于元素使用ajax重新加载div。ajax调用返回div的纯html并将其替换为当前的html。但这意味着替换执行的脚本。我认为脚本会在替换语句后停止执行。但它没有。执行替换语句后的代码行那么这些东西是如何工作的。您如何描述脚本block的生命周期? 最佳答案 当代码包含在script中时元素被求值时,代码求值的结果成为页面运行时环境的一部分。删除s

随机推荐