深入理解StatefulWidget生命周期

570 阅读5分钟

深入理解StatefulWidget生命周期

StatefulWidget 是 Flutter 框架中重要的组件类型之一,它具有丰富的生命周期方法,用于管理组件状态和处理 UI 更新。在 Flutter 中,StatefulWidget 是一种具有可变状态的组件,它可以根据内部状态的变化来更新 UI。与 StatelessWidget 不同,StatefulWidget 通过维护一个对应的 State 对象来管理状态,并通过调用 State 的方法来触发 UI 更新。

1.生命周期流程图

StatefulWidget生命周期 (1).png

1.1 State的创建

在前面[深入Flutter渲染更新机制二]中,我们了解到父Widget会解析子Widget并创建对应的Element对象添加到渲染树中;如下

Element

Untitled.png

StatefulWidget 对应的Element对象是StatefulElement;看下StatefulElement 的构造方法;

StatefulElement

Untitled 1.png

可以看到在创建StatefulElement 对象的时候创建了对应的State对象并且当state与对应的element,widget相关联起来了;这样在state中就可以直接访问element,widget对象了。

2. 生命周期方法

2.1. initState

在1.1中当element对象创建成功后,调用mount(Element? parent, Object? newSlot)方法将子element插入到渲染树中,看下ComponentElement 类对这个方法的复写;

ComponentElement

Untitled 2.png

父类调用了_firstBuild()方法,StatefulElement 复写了这个方法:

StatefulElement

Untitled 3.png

到这里终于看到了initState()方法的调用了;initState() 方法是在调用mount(Element? parent, Object? newSlot) 方法的过程中,是在State 对象被插入到渲染树中时被调用;这个方法只会调用一次;一般在这个方法内可以用于执行一些初始化操作,例如初始化变量、订阅事件或请求数据;

2.2. didChangeDependencies

在2.2中看到调用完initState() 方法后就调用了didChangeDependencies() 方法了;这个方法用于处理依赖关系的变化。当 Widget 所依赖的 InheritedWidget 发生变化时,该方法会被调用,我们可以在此方法中更新相关的数据或执行其他操作。

2.3. build

在调用完didChangeDependencies() 后调用了super._firstBuild() 方法,从父类方法接着往下看,最终调用的是performRebuild() 方法:

ComponentElement

Untitled 4.png

performRebuild() 方法内部调用了build() 方法,StatefulElement 复写了这个方法;

StatefulElement

Untitled 5.png

看到最终调用了state中的build()方法了;并将this传参过去了,这里可以看出state中的build(BuildContext context) 这个context是一个Element对象;

build 方法是 StatefulWidget 最常用的生命周期方法之一,用于构建并返回 Widget 的 UI 表示。在初始化阶段和每次调用 setState 后,build 方法都会被调用。

2.4. didUpdateWidget

当我们调用setState方法时会进行UI的更新;那是如何更新的呢?从[深入理解二]中我们可以看到最终调用的是updateChild(Element? child, Widget? newWidget, Object? newSlot) 方法;

Element

Untitled 6.png

Widget

Untitled 7.png

当child为null时即表示child第一次加载,而未挂载到渲染树上了,这时会走到流程1调用inflateWidget(newWidget, newSlot) 方法将child加载到渲染树上;当child不为null时表示已经将child挂载到渲染树上了,此时并不需要重新去解析挂载子child;只需要调用Widget.*canUpdate*(child.widget, newWidget) 方法判断下当前的Widget有没有发生变化;看下这个方法内部实现:可以看到它只比较了二个对象一个是runtimeType,一个是key;如果这二者都是相同则表示还是之前的Widget,不需要重新去挂载,只需要更新配置,走到流程2中;如果这二者不同,则表示当前的Wiget需要重新挂载,会走到流程3中,先将老的child从渲染树中去除,重新去挂载新child;其实这里也就解释了当我们给Widget的设置一个key时UI也会进行更新的原因了;进入流程2后,调用了child.update(newWidget) 方法,我们看下StatefulElement 对这个方法的复写

StatefulElement

Untitled 8.png

可以看到调用到didUpdateWidget(oldWidget) 方法了;所以可以看出didUpdateWidget 方法在 Widget 的配置发生变化时被调用;我们可以在此方法中比较新旧配置并执行相应的操作。

2.5. deactivate

deactivate 方法是在当从活动状态变成非活动状态时调用的,例如当从当前页面导航到一个新页面,当前页面的Widget就会调用**deactivate**方法进入到非活动状态,有点类似于从可见状态变成不可见状态时调用此方法。在 deactivate 方法中,可以执行一些清理工作和资源释放操作,例如取消订阅事件、停止动画等。这样可以确保在 State 对象不再处于活动状态时,相关资源得到正确的释放,避免不必要的资源占用。

2.6. dispose

StatefulElement

Untitled 9.png

可以看到当一个 StatefulWidget 被从组件树中被卸载永久移除时,对应的 State 对象会收到 dispose 方法的调用;可以理解为这个Widget的生命周期的终结了。

这里需要注意的是,deactivate 方法不同于 dispose 方法。deactivate 方法表示 State 对象不再处于活动状态,但仍然可以被重新激活并继续使用,而 dispose 方法则表示 State 对象即将被销毁,不再可用。

dispose 方法中,可以执行一些清理操作,例如取消订阅事件、关闭流(Stream)、释放资源等。这样可以确保在 State 对象被销毁时,相关的资源得到正确的释放,避免内存泄漏或资源浪费。

相关文章:

  1. 深入Flutter渲染更新机制一
  2. 深入Flutter渲染更新机制二
  3. 深入Flutter渲染-Android端
  4. 深入理解StatefulWidget生命周期