Consumer not updating with notifyListeners()

1,120

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 in main.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 to SleepSessionData
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 and SettingsWidget should work whenever notifyListeners() 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.

Share:
1,120
Ibrahim Yildirim
Author by

Ibrahim Yildirim

Mobile Application developer, mostly for iOS &amp; Android, with a flair for front end. www.iYildirim.com

Updated on January 01, 2023

Comments

  • Ibrahim Yildirim
    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 a ChangeNotifier 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 a setState is called.

    Widget Tree

    And a image of the screen for reference

    enter image description here

    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 both Consumer Widget and and watch() method. But it is as the notifyListeners() does not trigger the consumer/watcher. If i run a setState() (triggered by user input) the value from the the ChangeNotifier updates.

    Here's my MultiProvider in main.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
      kounex over 2 years
      I would assume it is because you are using the FutureProvider for your SleepSessionData and not the ChangeNotifierProvider. The documentation for FutureProvider 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 a ChangeNotifierProvider there as well and evaluate your async getSleepSessionData function before that
    • Ibrahim Yildirim
      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's read() and watch() 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
      Mohammed Alfateh over 2 years
      did you try to use listen:false?