Flutter 的生命周期

2021-10-26  本文已影响0人  QiShare

概述

生命周期是一个widget组件加载到卸载的整个周期,熟悉生命周期可以让我们在合适的时机做该做的事情。

在Flutter开发中,everything is widget,但我们一般都不用直接继承Widget类来实现一个新组件,我们通常会通过继承StatelessWidget或StatefulWidget来间接继承Widget类来实现。StatelessWidget和StatefulWidget都是直接继承自Widget类,而这两个类也正是Flutter中非常重要的两个抽象类,它们引入了两种Widget模型。此文主要介绍这两种widget的生命周期。

StatelessWidget

StatelessWidget是无状态的Widget,一旦创建就不会发生变化,所以无法提供setState修改组件的状态,它内部属性应声明为final,防止意外发生改变。所以StatelessWidget的生命周期只有一个,就是 build,build 是用来创建 Widget 的,但因为 build 在每次界面刷新的时候都会调用,所以不要在 build 里写业务逻辑,可以把业务逻辑写到你的 StatelessWidget 的构造函数里。其生命周期如下图:

image

StatefulWidget

StatefulWidget是有状态的Widget,它的state在发生变化时会重新渲染UI,提供setState方法修改组件的状态,它的生命周期主要在State这块,其生命周期如下图:

image

下面解释下各个函数:

注意:didChangeDependencies 方法调用后,组件的状态变为 dirty,立即调用 build 方法。

注意:此方法中应该只包含构建组件的代码,不应该包含其他额外的功能,尤其是耗时任务。

注意:Framework 调用完此方法后,会将组件设置为 dirty 状态,然后调用 build 方法。

实例展示

展示随机数的一个demo,点击随机按钮,更新随机数,打印此demo的生命周期函数的调用流程,代码如下:

import 'dart:math';

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      home: Scaffold(
        body: RandomPage(),
      ),
    );
  }
}

class RandomPage extends StatefulWidget {

  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return _RandomPageState();
  }
}

class _RandomPageState extends State<RandomPage> {
  final _randomBuild = Random();

  int _randomValue = 0;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    print('initState');
  }

 
  @override
  void didChangeDependencies() {
    // TODO: implement didChangeDependencies
    super.didChangeDependencies();
    print('didChangeDependencies');
  }

  @override
  Widget build(BuildContext context) {
    print('build');
    // TODO: implement build
    return Container(
      child: Padding(
        padding: EdgeInsets.only(top: 100),
        child: Center(
          child: Column(
            children: [
              Text('随机数: $_randomValue'),
              SizedBox(height: 200),
              TextButton(
                child: Text('切换随机数'),
                onPressed: () {
                  setState(() {
                    _randomValue = _randomBuild.nextInt(10000);
                  });
                },
              )
            ],
          ),
        ),
      ),
    );
  }

  @override
  void reassemble() {
    // TODO: implement reassemble
    super.reassemble();
    print('reassemble');
  }

  @override
  void didUpdateWidget(covariant RandomPage oldWidget) {
    // TODO: implement didUpdateWidget
    super.didUpdateWidget(oldWidget);
    print('didUpdateWidget');
  }

  @override
  void deactivate() {
    // TODO: implement deactivate
    super.deactivate();
    print('deactivate');
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    print('dispose');
  }
}

点击run首次启动,打印log如下:

flutter: initState
flutter: didChangeDependencies
flutter: build

点击切换随机数按钮,打印log如下:

flutter: build

点击切换随机数按钮,会调用setState(),setState会调用build重新构建widget。

点击hot reload按钮,打印log如下:

flutter: reassemble
flutter: didUpdateWidget
flutter: build

App生命周期

通过WidgetsBindingObserver的didChangeAppLifecycleState 可以获取App的生命周期状态。生命周期在AppLifecycleState类中。常用状态包含如下几个:

举例如下:

class _RandomPageState extends State<RandomPage>
    with WidgetsBindingObserver {

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance?.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance?.removeObserver(this);
    super.dispose();
  }

  void didChangeAppLifecycleState(AppLifecycleState state) async {
    if (state == AppLifecycleState.resumed) {
      getData();
    }
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    throw UnimplementedError();
  }
  
  void getData() {
    
  }
}

记得注册和移除监听。

生命周期相关的一些注意点

@override 
void initState() { 
    super.initState(); 
    WidgetsBinding.instance.addPostFrameCallback((_) => {}); 
}

mounted 是 State 对象中的一个属性,此属性表示当前组件是否在树中(在创建 State 之后,调用 initState 之前,Framework 会将 State 和 BuildContext 进行关联),当 Framework 调用 dispose 时,mounted 被设置为 false,表示当前组件已经不在树中。

createState 函数执行完毕后表示当前组件已经在组件树中,属性 mounted 被 Framework 设置为 true,平时写代码时或者看其他开源代码时经常看到如下代码:

if(mounted){ 
    setState(() { ... });
}

强烈建议:在调用 setState 时加上 mounted 判断。

为什么要加上如此判断?因为如果当前组件未插入到树中或者已经从树中移除时,调用 setState 会抛出异常,加上 mounted 判断,则表示当前组件在树中。

dirty 表示组件当前的状态为 脏状态,下一帧时将会执行 build 函数,调用 setState 方法或者 执行 didUpdateWidget 方法后,组件的状态为 dirty。

clean 与 dirty 相对应,clean 表示组件当前的状态为干净状态,clean 状态下组件不会执行 build 函数。

上一篇 下一篇

猜你喜欢

热点阅读