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