Flutter NoSuchMethodError: The method ‘markNeedsBuild‘ was called on null

淡淡的烟草味﹌ 2022-10-30 08:30 123阅读 0赞

这个错误常出现在异步任务(Future)处理,比如某个页面请求一个网络API数据,根据数据刷新 Widget State。

异步任务结束在页面被pop之后,但没有检查State 是否还是 mounted,继续调用 setState 就会出现这个错误。

示例代码

一段很常见的获取网络数据的代码,调用 requestApi(),等待Future从中获取response,进而setState刷新 Widget:








  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
  1. class AWidgetState extends State<AWidget> {
    // …
    var data;
    void loadData() async {
    var response = await requestApi(…);
    setState((){
    this.data = response.data;
    })
    }
    }

原因分析

response 的获取为async-await异步任务,完全有可能在AWidgetStatedispose之后才等到返回,那时候和该State 绑定的 Element 已经不在了。故而在setState时需要容错。

解决办法: setState之前检查是否 mounted








  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
  1. class AWidgetState extends State {
    // …
    var data;
    void loadData() async {
    var response = await requestApi(…);
    if (mounted) {
    setState((){
    this.data = response.data;
    })
    }
    }
    }

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

比如,在 FrameCallback里执行一个动画(AnimationController):








  1. 1
    2
    3
    4
    5
    6
  1. @override
    void initState(){
    WidgetsBinding.instance.addPostFrameCallback((_) {
    if (mounted) _animationController.forward();
    });
    }

AnimationController有可能随着 State 一起 dispose了,但是FrameCallback仍然会被执行,进而导致异常。

又比如,在动画监听的回调里搞点事:








  1. 1
    2
    3
    4
    5
    6
    7
    8
  1. @override
    void initState(){
    _animationController.animation.addListener(_handleAnimationTick);
    }

    void _handleAnimationTick() {
    if (mounted) updateWidget(…);
    }

同样的在_handleAnimationTick被回调前,State 也有可能已经被dispose了。

发表评论

表情:
评论列表 (有 0 条评论,123人围观)

还没有评论,来说两句吧...

相关阅读