Flutter 构建子组件时触发setState报错,如何向父组件传计算结果
问题根因
触发setState() or markNeedsBuild() called during build的核心原因是,Flutter的build阶段为纯UI计算流程,不允许同步触发任何会标记组件需要重建的操作。当前实现直接在子组件的build流程中,调用了会触发父组件setState的widget.setmsg(msg)方法,完全违背了Flutter的组件构建流程规范。
两种核心需求的实现方案
方案1:直接在当前子组件界面上显示计算得到的msg
无需跨组件传值,改动量最小,完全不会触发重建相关的报错:
- 保留
_renderKeypoints()原有关键点渲染、msg计算的全部逻辑 - 将计算得到的msg对应的展示组件,直接合并到Stack的children列表中即可
- 参考修改后的核心代码:
@override Widget build(BuildContext context) { String msg = ""; List<Widget> _renderKeypoints() { // 完全保留原有关键点坐标换算、msg赋值的逻辑,不做改动 } // 先拿到关键点渲染列表 final keypointWidgets = widget.model == posenet ? _renderKeypoints() : <Widget>[]; return Stack( children: [ ...keypointWidgets, // 新增msg展示组件 Positioned( top: 20, left: 0, right: 0, child: Center( child: Container( padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), color: Colors.black54, child: Text( msg, style: const TextStyle(color: Colors.white, fontSize: 16), ), ), ), ) ], ); }
方案2:正确将msg传递给父组件(无build阶段报错)
如果确实需要跨组件把msg传给父组件,不能在build的同步执行流程里直接调用回调,需要把回调的执行时机延后到当前帧渲染完成之后,标准实现方式为:
- 在
_renderKeypoints()内完成msg计算的位置(也就是try/catch块结束后),将直接调用回调的逻辑替换为帧回调:
// 原来直接写的 widget.setmsg(msg); 替换为以下代码 WidgetsBinding.instance.addPostFrameCallback((_) { // 等当前帧的build、渲染全流程走完,再触发回调 widget.setmsg(msg); });
- 原理:
addPostFrameCallback会把回调排到当前帧UI渲染完成后的事件循环中执行,完全脱离build的执行周期,不会触发build期间调用setState的报错。 - 可选优化:计算msg的本质是业务逻辑,不属于UI渲染流程,可将这部分逻辑移出build方法,在
widget.results(姿态识别结果)更新时再执行计算,避免每次组件重建时重复运行计算逻辑,降低性能损耗。
代码小提示
当前实现中kx数组初始化后立刻清空,若姿态识别结果为空、关键点数量不足,后续取kx[3]、kx[5]、kx[11]时容易触发数组越界异常,可在取值前提前判断数组长度,减少不必要的异常捕获开销。
内容的提问来源于stack exchange,提问作者Rawan
相关产品推荐
相关产品推荐

