Flutter中init调用Provider重置函数出现build期间调用错误的原因
错误原因解析
出现"setState() or markNeedsBuild() called during build."错误的核心原因是:在Widget树的构建流程中触发了UI重建请求,具体到你的代码场景:
- 你在有状态Widget的
initState方法中直接调用了getPlotsGraphDataAccordingToCategoryAndDate函数,该函数开头就同步执行了Provider的resetPerticularCategoryDataAccordingDate方法。 resetPerticularCategoryDataAccordingDate内部调用了notifyListeners(),这个方法会通知所有依赖该Provider的Widget立即触发重建。- 但此时当前Widget的初始化流程(包括
initState执行阶段)尚未完成,整个Widget树还处于构建状态,这种情况下触发重建请求会和当前的构建流程产生冲突,进而抛出该错误。
另外你的Provider代码存在冗余逻辑:resetPerticularCategoryDataAccordingDate和setperticularCategoryDataAccordingDate方法不需要加Future和async,内部都是同步操作,异步包装只会增加不必要的逻辑复杂度。
修复方案
方案1:延迟到Widget构建完成后执行
在initState中使用WidgetsBinding.instance.addPostFrameCallback,将函数调用延迟到当前Widget构建完成后的下一帧执行:
@override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { getPlotsGraphDataAccordingToCategoryAndDate(context, CategoryId, CategoryName, date); }); }
方案2:简化Provider的同步方法
将Provider中的两个异步方法改为同步,移除不必要的async和Future:
class RepresentationProvider extends ChangeNotifier { List perticularCategoryDataAccordingDate = []; void setperticularCategoryDataAccordingDate(data) { perticularCategoryDataAccordingDate.add(data); notifyListeners(); print("object here $perticularCategoryDataAccordingDate"); } void resetPerticularCategoryDataAccordingDate() { perticularCategoryDataAccordingDate = []; notifyListeners(); } }
方案3:使用调度器将更新放入事件循环
通过SchedulerBinding将状态更新操作放到构建流程之外的事件循环中执行:
@override void initState() { super.initState(); SchedulerBinding.instance.scheduleTask(() { getPlotsGraphDataAccordingToCategoryAndDate(context, CategoryId, CategoryName, date); }, Priority.touch); }
核心逻辑说明
Flutter的Widget构建流程是线性的,在initState、build等生命周期方法执行期间,Widget树处于不可变的构建状态,此时禁止触发依赖Widget的重建请求(比如调用setState或notifyListeners)。必须等当前Widget构建完成,进入事件循环队列后,才能安全触发这类更新操作。
内容的提问来源于stack exchange,提问作者Shafqat Ali
相关产品推荐
相关产品推荐

