在initState中使用context.read<T>或Provider.of<T>(context, listen: false)调用Provider方法触发构建异常的问题求助
我完全懂你现在的困惑——明明已经用了listen: false,按道理不该监听Provider的状态变化,怎么还会抛出“setState() or markNeedsBuild() called during build”的异常?咱们来拆解下问题根源和解决办法:
问题到底出在哪?
你用context.read<UtilsProvider>()确实不会让PlayerAvatar监听Provider的状态变化,但问题出在调用时机上:initState是在Widget第一次构建的过程中同步执行的,你在里面直接调用了loadimage方法,而这个方法里第一行就同步修改了utilsState并调用了notifyListeners()。
这时候,哪怕你的PlayerAvatar没在监听,只要Widget树里还有其他监听了UtilsProvider的组件,notifyListeners()就会通知它们去更新状态。如果这些组件刚好处于当前的构建周期中,就会触发“在构建期间调用setState”的断言错误。
简单说:不是你的PlayerAvatar自己出问题,而是你在构建过程中触发了其他监听组件的更新,导致了全局的构建冲突。
怎么解决?
最稳妥的办法是把loadimage的调用延迟到当前Widget的第一次构建完成后再执行,用WidgetsBinding.instance.addPostFrameCallback就能实现:
修改你的initState代码:
@override void initState() { super.initState(); // 把请求放到当前帧构建完成后执行 WidgetsBinding.instance.addPostFrameCallback((_) { context.read<UtilsProvider>().loadimage(widget.image!).then( (value) { if (mounted) { setState(() { imageToShow = value; }); } }, ); }); }
这样一来,loadimage会等到整个Widget的第一次构建完成后才执行,这时候调用notifyListeners()就不会和当前的构建周期冲突了。
额外补充
你提到以后会用到UtilsProvider的变量,到时候可以正常用Consumer或者context.watch来监听状态变化,现在的问题完全是调用时机导致的,和listen: false本身的用法无关。
备注:内容来源于stack exchange,提问作者l.diazborg

