You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 18:50:26