消费者未使用 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()
被调用,您的 PlaylistSelector
和 SettingsWidget
中的代码就应该可以工作,因为侦听器现在已正确绑定。
so when the future completes it will overwrite this value
但这并不完全是问题的根本原因。即使我们预先创建 SleepSessionData
实例并在 FutureProvider
中创建相同的实例 return,问题仍然存在。
我在 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()
被调用,您的PlaylistSelector
和SettingsWidget
中的代码就应该可以工作,因为侦听器现在已正确绑定。
so when the future completes it will overwrite this value
但这并不完全是问题的根本原因。即使我们预先创建 SleepSessionData
实例并在 FutureProvider
中创建相同的实例 return,问题仍然存在。