Flutter中ChangeNotifier/Provider仅获初始值,notifyListeners无效
问题原因及解决方案
核心问题:SettingsSlider 使用了独立的 VolumeModel 实例
在SettingsSlider组件中,你手动创建了一个全新的VolumeModel对象:
VolumeModel volume = VolumeModel();
这个实例和你在MultiProvider中注册的全局实例完全无关。当你调用widget.volume.changeVolume(...)时,修改的是这个本地实例的数值,而PrimaryScreenController监听的是全局的那个实例,所以自然收不到更新通知。
次要问题:Slider 值未与模型实时同步
当前Slider的value绑定的是widget.volumeValue,这是一个传入的静态值,无法实时反映模型中的最新音量。正确的做法应该是直接从全局VolumeModel中读取对应的值。
额外优化点:PrimaryScreenController 重复执行播放逻辑
由于你在build方法中调用了playBackgroundMusic(),而listen: true会导致每次模型更新时build重新执行,这会重复触发背景音乐播放。建议将该调用移至initState中,确保只执行一次。
修正后的 SettingsSlider 代码
class SettingsSlider extends StatefulWidget { final String volumeLabel; const SettingsSlider({super.key, required this.volumeLabel}); @override State<SettingsSlider> createState() => _SettingsSliderState(); } class _SettingsSliderState extends State<SettingsSlider> { @override Widget build(BuildContext context) { // 获取全局的 VolumeModel 实例 final volumeModel = Provider.of<VolumeModel>(context); // 根据标签获取对应音量值 double currentValue = 0; switch(widget.volumeLabel) { case VolumeModel.backgroundMusicKey: currentValue = volumeModel.currentBackgroundMusicVolume; break; case VolumeModel.speechAudioKey: currentValue = volumeModel.currentSpeechAudioVolume; break; case VolumeModel.soundEffectsKey: currentValue = volumeModel.currentSoundEffectsVolume; break; } return Slider( value: currentValue, min: 0, max: 100, label: currentValue.round().toString(), activeColor: const Color(0xffDF9676), thumbColor: const Color(0xff57CC85), onChanged: (double value) { // 直接调用全局模型的更新方法 volumeModel.changeVolume(value, widget.volumeLabel); }, ); } }
修正后的 PrimaryScreenController 代码
@override void initState() { super.initState(); // 仅在初始化时播放一次背景音乐 playBackgroundMusic(); } @override Widget build(BuildContext context) { double vol = Provider.of<VolumeModel>(context, listen: true).currentBackgroundMusicVolume; print(vol); return MaterialApp( home: Scaffold( body: PageView( controller: _controller, physics: const NeverScrollableScrollPhysics(), children: [ const HomeScreen(), LearnScreen(audioPlayer), SettingsScreen(), ], ), ), ); }
调整 SettingsSlider 的调用方式
现在无需传入volumeValue,只需传递对应的标签:
SettingsSlider(volumeLabel: VolumeModel.backgroundMusicKey)
内容的提问来源于stack exchange,提问作者egm_along
相关产品推荐
相关产品推荐

