Flutter - State类 之mounted

2020-04-02  本文已影响0人  停心阁

State类 是当 Widget 被渲染或者在其生命周期中状态改变时,能同步读到相关信息的对象。当实例StatefulWidget 时必须保证能正确使用 State.setState 来告知该 Widget的状态发生了变化。

当渲染这个 StatefulWidget 并将其插入View 树中,会调用 StatefulWidget.createState 然后,framework 就会创建一个 State 对象。 因为一个 Widget 可以被 inflated 多次,比如说 这个 FavoriteWidget 可以被多个地方用到,所以这里会存在多个 _FavoriteWidgetState 与之绑定。同样,当 StatefulWidget 被移除出 Views 树的时候,然后又重新插入,这时候 framework 会再次调用StatefulWidget.createState来创建一个新的 State 对象。


这个新的 State 对象将会绑定一个 BuildContext ,这个绑定是永久的。 State 永远也不会改变其 BuildContext (所以它的属性中,contenxt是只读的。可以把这个理解成 Widget 在 Views 树中的位置,文档中是 The location in the tree where this widget builds.)但是, BuildContext 自身却是可以改变的,可以因为 Widget 在树中的位置变化而变化。由此,State 有一个属性是 mounted 表明 State 当前是否正确绑定在View树中。当创建 State 对象,并在调用 State.initState 之前,framework 会根据 BuildContext 来标记 mounted,然后在 State的生命周期里面,这个 mounted 属性不会改变,直至 framework 调用 State.dispose,当改变之后, State 对象再也不会调用 build 方法,而且当 mounted = false 时,调用 State.setState 会报错。

接下来看一段代码:

class CHWidgetState extends State<CHWidget> {
  // ...
  var data;
  void loadData() async {
    var response = await requestApi(...);
    setState((){
      this.data = response.data;
    })
  }
}

这段看似没有问题,但是放在这里肯定是有原因的:
response 的获取为async-await异步任务,完全有可能在CHWidgetState被 dispose之后才等到返回,那时候和该State 绑定的 Element 已经不在了,这时候会出现错误信息:NoSuchMethodError: The method 'markNeedsBuild' was called on null.

故而这个mounted检查很重要,其实只要涉及到异步还有各种回调(callback),都不要忘了检查该值。


class AWidgetState extends State {
  // ...
  var data;
  void loadData() async {
    var response = await requestApi(...);
    if (mounted) {
      setState((){
        this.data = response.data;
      })
    }
  }
}
上一篇下一篇

猜你喜欢

热点阅读