消费者未使用 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 而不是ChangeNotifierProviderFutureProvider 的文档说:“当未来完成时,接受未来并更新家属。” - 所以它只在未来更新时更新,而不是模型/类本身。我建议在那里也使用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>());
   // ..

那么PlaylistSelectorSettingsWidget 中的代码应该可以在调用notifyListeners() 时工作,因为现在监听器已正确绑定。

所以当future完成时它会覆盖这个值

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

【讨论】:

【参考方案2】:

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

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

因此,更好的方法是不使用FutureProvider,而是使用ChangeNotifierProvider,然后开始在SleepSessionData 类中加载数据。

【讨论】:

以上是关于消费者未使用 notifyListeners() 进行更新的主要内容,如果未能解决你的问题,请参考以下文章

提供者 NotifyListeners 不更新消费者

NotifyListeners 未更新 Flutter Widget

Flutter:`notifyListeners`不更新列表

notifyListeners() 不向 UI 返回数据

颤振 notifyListeners 似乎不起作用

Provider 调用 notifyListeners() 时 Flutter View 不更新视图