Flutter渲染机制分析(一) —— setState() 详解

505 阅读2分钟

setState 是什么

先看一下官方对 setSatate 的说明

/// Notify the framework that the internal state of this object has changed.
/// Whenever you change the internal state of a [State] object, make the
/// change in a function that you pass to [setState]:
/// ```dart
///  setState(() { _myState = newValue; });
/// ```

通知框架此对象的内部状态已更改。
每当你更改[state]对象的内容状态时, 在传递给[setState]的函数中更改需要改变的状态.

setState是如何工作的

@protected
void setState(VoidCallback fn) {
  final Object? result = fn() as dynamic;
  _element!.markNeedsBuild();
}

setState 函数内容非常简单, 除去 assert 关键断言后, 关键代码就两行. 执行传参 fn 回调
关键代码在 _element!.markNeedsBuild 这里暂时不做解释, 只需要知道调用调用次方法执行的重新渲染即可

setState为什么需要做mounted判断

/// Whether this [State] object is currently in a tree.
bool get mounted => _element != null;

很简单的一行代码, 保证当前_element 不为null也就是Element在树中, 这里的Tree 指的是 Element Tree.
调用_element!.markNeedsBuild 重新渲染的前提是_element 不为空, mounted 刚好就是做了这个判断, 这也就是有时setState需要加mounted判断的原因
看着这里就会疑惑, _element 是什么, _element 其实很简单, 代表的就是 StatefulElement? _element;
_element又是什么时候创建, 什么时候为空的呢, 下面就来进行分析.

StatefulElement 是什么

看到StatefulElement 大家可能都会想到StatefulWidget, 没错这里的 StatefulElement 对应的就是根据StaatefulWidget创建的, 它们在Flutter 三棵树中就是对应关系.

abstract class StatefulWidget extends Widget {
  /// Initializes [key] for subclasses.
  const StatefulWidget({ super.key });

  @override
  StatefulElement createElement() => StatefulElement(this);

  @protected
  @factory
  State createState(); // ignore: no_logic_in_create_state, this is the original sin
}

/// An [Element] that uses a [StatefulWidget] as its configuration.
class StatefulElement extends ComponentElement {
  /// Creates an element that uses the given widget as its configuration.
  StatefulElement(StatefulWidget widget)
      : _state = widget.createState(),
        super(widget) {
          state._element = this;
          state._widget = widget;
        }
}

看到这里可以发现, StatefulWidgetcreateElement 创建了 StatefulElement, StatefulElement 又在构造里通过 createState 创建了 State, 最后把 StatefulElement 自己赋值给了State, StatefulWidget 赋值给 State, 这里就是StateStatefulElement _element 的由来了.

至于 state 中的 _element 值又是何时置空的, 可以看下面的代码;

abstract class ComponentElement extends Element {
  @override
  void mount(Element? parent, Object? newSlot) {
    super.mount(parent, newSlot);
  	_firstBuild();
  }
}

class StatefulElement extends ComponentElement {
  @override
  void _firstBuild() {
    try {
      _debugSetAllowIgnoredCallsToMarkNeedsBuild(true);
      final Object? debugCheckForReturnedFuture = state.initState() as dynamic;
    } finally {
      _debugSetAllowIgnoredCallsToMarkNeedsBuild(false);
    }
    state.didChangeDependencies();
    super._firstBuild();
  }
  
  @override
  void unmount() {
  	super.unmount();
    state.dispose();
    state._element = null;
    _state = null;
  }
}

unmount中我们看到了 state._element 被置空, _state 被置空
unmountmount 我们也可以看到很熟悉的State的生命周期函数, initState, didChangeDependencies, dispose 它们就是在这里被调用的

mount 实际调用的是 StatefulElement 的父类 ComponentElementmount, StatefulElement并没有重写 mount

至于unmountmount 又是何时被调用的, 这个就涉及到更大的知识点了, 感兴趣的可以了解 Flutter unApp做了什么 和 Flutter 运行流程来探寻 ement是何时被挂载又是何时被移除的.