Flutter Provider跨Widget树监听报错,添加listen:false仍无效
报错信息
The following assertion was thrown while calling onSubmitted for TextInputAction.done:
Tried to listen to a value exposed with provider, from outside of the widget tree.
This is likely caused by an event handler (like a button's onPressed) that called
Provider.of without passinglisten: false. To fix, write:
Provider.of(context, listen: false);
It is unsupported because may pointlessly rebuild the widget associated to the
event handler, when the widget tree doesn't care about the value.
The context used was: Boxes(dependencies: [_InheritedProviderScope<Counter?>], state:
_BoxesState#274b3)
'package:provider/src/provider.dart':
Failed assertion: line 274 pos 7: 'context.owner!.debugBuilding ||
listen == false ||
debugIsInInheritedProviderUpdate'
问题根源
你在TextField的onSubmitted事件回调里用了context.watch<Counter>(),这个方法的作用是监听Counter实例的变化并触发widget重建,但它只能在widget的build方法或构建相关的生命周期里使用。事件回调属于用户交互触发的逻辑,不在widget树的构建流程中,所以会触发这个断言错误。
你之前加的Provider.of<Counter>(context, listen: false);根本没解决问题——因为你只是获取了实例但没用到它,真正的错误来源是后面的context.watch调用。
修复方案
把事件回调里的context.watch<Counter>()替换成不监听的读取方式,两种可选:
方法1:用Provider.of指定listen: false
TextField( controller: _textController, style: const TextStyle(color: Colors.white), decoration: const InputDecoration( border: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(40.0)), ), labelText: "Enter here", ), onSubmitted: (value) { setState(() { _boxStorage += "- ${_textController.text}\n"; // 替换watch为带listen: false的Provider.of final counter = Provider.of<Counter>(context, listen: false); _storage.insert(counter.count, _boxStorage); _saveSharedPreferences(); _textController.clear(); }); } ),
方法2:用context.read(Provider提供的快捷方法,等价于listen: false)
TextField( controller: _textController, style: const TextStyle(color: Colors.white), decoration: const InputDecoration( border: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(40.0)), ), labelText: "Enter here", ), onSubmitted: (value) { setState(() { _boxStorage += "- ${_textController.text}\n"; // 用read替代watch final counter = context.read<Counter>(); _storage.insert(counter.count, _boxStorage); _saveSharedPreferences(); _textController.clear(); }); } ),
关键说明
watch:用于widget构建时,监听状态变化自动触发重建,绝对不能在事件回调里用read/Provider.of(..., listen: false):仅读取当前状态值、不监听变化,适合在事件处理、异步逻辑中使用
内容的提问来源于stack exchange,提问作者Cezary Dąbek

