消费者未使用 notifyListeners() 进行更新
Posted
技术标签:
【中文标题】消费者未使用 notifyListeners() 进行更新【英文标题】:Consumer not updating with notifyListeners() 【发布时间】:2021-11-12 06:33:06 【问题描述】:我在 Flutter 中为我的应用创建了一个简单的 Widget Tree 来解决这个问题。
问题是,当我在 SleepSessionData
(这是一个 ChangeNotifier
类)中调用该方法时,消费者不会被解雇。
如果在同一个小部件中调用包含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
Widget 和watch()
方法。但这是因为notifyListeners()
不会触发消费者/观察者。如果我运行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
而不是ChangeNotifierProvider
。 FutureProvider
的文档说:“当未来完成时,接受未来并更新家属。” - 所以它只在未来更新时更新,而不是模型/类本身。我建议在那里也使用ChangeNotifierProvider
并在此之前评估您的异步getSleepSessionData
函数
@kounex 感谢您的回复!但我不认为这是问题所在。如果从同一个小部件中调用 read()
和 watch()
,则提供程序和 notifyListeners()
工作正常。但在这种情况下,它没有。但为了确定,我会测试一下!
您是否尝试使用listen:false
?
【参考方案1】:
您不应将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>());
// ..
那么PlaylistSelector
和SettingsWidget
中的代码应该可以在调用notifyListeners()
时工作,因为现在监听器已正确绑定。
所以当future完成时它会覆盖这个值
但这并不完全是问题的根本原因。即使我们事先创建了SleepSessionData
实例并在FutureProvider
中返回相同的实例,问题仍然存在。
【讨论】:
【参考方案2】:您只有一个 FutureProvider
来保存 SleepSessionData
,因此它只会在未来完成时更新一次。
如果您希望 ui 更新未来结果的更改,那么您需要监听这些更改,例如使用 ChangeNotifierProvider
。
此外,您还为 FutureProvider
提供了一个带有 SleepSessionData
新实例的初始数据,因此当未来完成时,它将覆盖该值,这意味着您对初始值执行的任何操作都将被丢弃。
因此,更好的方法是不使用FutureProvider
,而是使用ChangeNotifierProvider
,然后开始在SleepSessionData
类中加载数据。
【讨论】:
以上是关于消费者未使用 notifyListeners() 进行更新的主要内容,如果未能解决你的问题,请参考以下文章
NotifyListeners 未更新 Flutter Widget