Home > Mobile >  How can I get a changenotifier using a futureprovider with riverpod?
How can I get a changenotifier using a futureprovider with riverpod?

Time:06-05

I am using shared_preferences for my app and I have made a Settings class with helper methods. As part of the Settings method I use Settings.create to generate my SharedPreferences. It looks like this:

class Settings extends ChangeNotifier {
  final SharedPreferences prefs;

  Settings(this.prefs);

  static Future<Settings> create() async {
    var prefs = await SharedPreferences.getInstance();
    return Settings(prefs);
  }
  
  // ### Helper Methods ###
}

I have used this post to try a solution and have come up with this:

FutureProvider<Settings> createSettings = FutureProvider<Settings>((ref) {
  return Settings.create();
});

ChangeNotifierProvider<Settings> settingsProvider = ChangeNotifierProvider<Settings> ((ref) {
  final settingsInstance = ref.watch(createSettings).maybeWhen(
        data: (value) => value,
        orElse: () => null,
      );
  return Settings(settingsInstance.prefs);
});

The problem I have now run into is that I get an Error because null is returned as long as the future has not completed.

I have hit a wall and am out of ideas. Does anyone have an idea on how to solve this?

CodePudding user response:

Yeah, two options. Depending on the trade-offs you want to make.

Options

Option 1 (just wait)

In main.dart inside the Future<void> main() async {} function, just wait for the call to get shared prefs and then manually set the state in a your providers (using a state provider).

So that looks like:

(providers.dart)

final settingsProvider = StateProvider<Settings>((_) => defaultValue);

// ^ You can also make the above nullable if you don't have a reasonable default. But to be fair, this default will never be called if you're always setting it in main.

(main.dart)

Future<void> main() async {
  final settings = await Settings.create();
  final container = ProviderContainer();
  container.read(settingsProvider.state).state = settings;
}

Option 2 (same idea, just don't wait)

The same as the above code, but don't wait in main. Just don't wait. Here's the difference:

(main.dart)

Future<void> main() async {
  final container = ProviderContainer();
  Settings.create().then((settings){
    container.read(settingsProvider.state).state = settings;
  });
  // The rest of your code...
  runApp();
}

Overview / Comparison

Option #1 is more simple to work with, but you may not be okay with waiting if you want a fast startup. But I doubt that it matters. In that case, if you have reasonable defaults, then use option #2

For the code on using Riverpod in main(), please reference this Github issue comment: https://github.com/rrousselGit/riverpod/issues/202#issuecomment-731585273

  • Related