消费者未使用 notifyListeners() 进行更新

Consumer not updating with notifyListeners()

我在 flutter 中为我的应用程序创建了一个简单的 Widget Tree 来解决这个问题。

问题是当我在我的 SleepSessionData 中调用方法时 ChangeNotifier class,消费者不会被解雇。

如果在同一个小部件中调用包含 notifyListeners() 的方法没有问题,但是当它是两个同级小部件时,除非调用 setState,否则消费者不会更新。

和屏幕图像供参考

SleepSessionData 扩展 ChangeNotifier

void updateSelectedPlaylists(List<String> selectedPlaylists) {
    this.selectedPlaylists = selectedPlaylists;
    notifyListeners();
    _saveData();
}

PlaylistSelectorWidget

void selectedIndex(int index) {
    ...
    context.read<SleepSessionData>().updateSelectedPlaylists(_selectedPlaylistIds);
    setState(() {});
}

在我的 SettingsWidget 中,我尝试同时使用 Consumer 小部件和 watch() 方法。但它是因为 notifyListeners() 不会触发 consumer/watcher。如果我 运行 a setState()(由用户输入触发)来自 ChangeNotifier 的值更新。

这是我在 main.dart

中的 MultiProvider
child: MultiProvider(
  providers: [
    ChangeNotifierProvider<MySleepData>(create: (_) => MySleepData()),
    ChangeNotifierProvider<DirectoryData>(create: (_) => DirectoryData()),
    FutureProvider<UserData>(
        create: (_) => LocalPersistence.getUserData(),
        initialData: UserData()),
    FutureProvider<SleepSessionData>(
      create: (_) => LocalPersistence.getSleepSessionData(),
      initialData: SleepSessionData(),
    )
  ],

您只有一个 FutureProvider 包含 SleepSessionData,因此它只会在未来完成时更新一次。 如果您希望 ui 更新未来结果的变化,那么您需要监听这些变化,例如使用 ChangeNotifierProvider.

此外,您还使用 SleepSessionData 的新实例为 FutureProvider 提供初始数据,因此当未来完成时,它将覆盖该值,这意味着您对初始值执行的任何操作都将被丢弃。

因此,更好的方法是不使用 FutureProvider,而是使用 ChangeNotifierProvider,然后开始在 SleepSessionData [=24= 中加载数据].

您不应该将 ChangeNotifier 包裹在 FutureProvider 中以使其正常工作。

当您将 ChangeNotifier 包裹在 FutureProvider 中时,它会以某种方式中断向 ChangeNotifiers 添加侦听器的过程。当用 FutureProvider 包装 ChangeNotifier 时,你总是得到 0 个听众。 (您可以通过调试和检查 ChangeNotifier 实例的 listeners 属性 来验证这一点。)这就是为什么在调用 notifyListeners() 时,小部件不会重新呈现,因为它们是不是您的 ChangeNotifier 实例的监听器。

所以你的问题的解决方案是:

  • main.dart
  • 中使用ChangeNotifier
child: MultiProvider(
  providers: [
    ChangeNotifierProvider<MySleepData>(create: (_) => MySleepData()),
    ChangeNotifierProvider<DirectoryData>(create: (_) => DirectoryData()),
    ChangeNotifierProvider<UserData>(create: (_) => UserData()),
    ChangeNotifierProvider<SleepSessionData>(create: (_) => SleepSessionData()),
  ],
  • SessionSetupPage 中,您从本地存储获取数据并将更改加载到 SleepSessionData
loadData(SleepSessionData sessionData) async {
    final data = await LocalPersistence.getData();
    sessionData.setData(data);
}

Widget build(BuildContext context) {
   loadData(context.read<SleepSessionData>());
   // ..
}
  • 那么只要 notifyListeners() 被调用,您的 PlaylistSelectorSettingsWidget 中的代码就应该可以工作,因为侦听器现在已正确绑定。

so when the future completes it will overwrite this value

但这并不完全是问题的根本原因。即使我们预先创建 SleepSessionData 实例并在 FutureProvider 中创建相同的实例 return,问题仍然存在。