Consumer not updating with notifyListeners()
You shouldn't wrap your ChangeNotifier
inside the FutureProvider
in order to make it works properly.
When you wrap the ChangeNotifier
inside the FutureProvider
it breaks the process of adding listeners to the ChangeNotifiers
somehow. You always get 0 listeners when wrapping ChangeNotifier
with FutureProvider
. (You can verify this by debugging and check the listeners
property of your ChangeNotifier
instance.) That's why when calling notifyListeners()
, the widgets don't rerender since they're not the listener of your ChangeNotifier
instance.
So the solution to your problem would be:
- Use
ChangeNotifier
inmain.dart
child: MultiProvider(
providers: [
ChangeNotifierProvider<MySleepData>(create: (_) => MySleepData()),
ChangeNotifierProvider<DirectoryData>(create: (_) => DirectoryData()),
ChangeNotifierProvider<UserData>(create: (_) => UserData()),
ChangeNotifierProvider<SleepSessionData>(create: (_) => SleepSessionData()),
],
- In the
SessionSetupPage
, you get the data from your local store and load the changes toSleepSessionData
loadData(SleepSessionData sessionData) async {
final data = await LocalPersistence.getData();
sessionData.setData(data);
}
Widget build(BuildContext context) {
loadData(context.read<SleepSessionData>());
// ..
}
- Then the code in your
PlaylistSelector
andSettingsWidget
should work whenevernotifyListeners()
is called since the listeners are bound correctly now.
so when the future completes it will overwrite this value
This is not totally the root cause of the issue though. Even if we create the SleepSessionData
instance beforehand and return the same instance inside the FutureProvider
, the problem still persists.
Ibrahim Yildirim
Mobile Application developer, mostly for iOS & Android, with a flair for front end. www.iYildirim.com
Updated on January 01, 2023Comments
-
Ibrahim Yildirim over 1 year
I have created a simple Widget Tree of my app in flutter that adresses the issue.
The issue is that when I call the method in my
SleepSessionData
which is aChangeNotifier
class, the consumer does not get fired.There is no issue if the method containing
notifyListeners()
is called within the same widget, but when it is two sibling widgets the consumer does not update unless asetState
is called.And a image of the screen for reference
SleepSessionData extends ChangeNotifier
void updateSelectedPlaylists(List<String> selectedPlaylists) { this.selectedPlaylists = selectedPlaylists; notifyListeners(); _saveData(); }
PlaylistSelectorWidget
void selectedIndex(int index) { ... context.read<SleepSessionData>().updateSelectedPlaylists(_selectedPlaylistIds); setState(() {}); }
In my
SettingsWidget
I tried using bothConsumer
Widget and andwatch()
method. But it is as thenotifyListeners()
does not trigger the consumer/watcher. If i run asetState()
(triggered by user input) the value from the theChangeNotifier
updates.Here's my
MultiProvider
inmain.dart
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(), ) ],
-
kounex over 2 yearsI would assume it is because you are using the
FutureProvider
for yourSleepSessionData
and not theChangeNotifierProvider
. The documentation forFutureProvider
says: "Takes a Future and updates dependents when the future completes." - so it only updates when the future updates but not the model / class itself. I suggest to use aChangeNotifierProvider
there as well and evaluate your asyncgetSleepSessionData
function before that -
Ibrahim Yildirim over 2 years@kounex Thanks for your reply! But I don't think that's the issue. The provider and
notifyListeners()
works fine if it'sread()
andwatch()
is called from within the same widget. But in this case it doesn't. But I will test it out just to be sure! -
Mohammed Alfateh over 2 yearsdid you try to use
listen:false
?
-