💡
起動時にRiverpodに初期値を設定する実装
起動時にRiverpodに初期値を設定する実装
-
下記の課題感があった
- アプリ起動した際に、Riverpodにすでにデータが設定されている状態にしたい
-
具体的には、
- FutureProviderで対応していたが、非asyncなProviderで楽に取り扱いたい
(UI側でのFutureを減らしたい) - sharedPreferenceをProvider管理していたがasyncなのが嫌だった
- FutureProviderで対応していたが、非asyncなProviderで楽に取り扱いたい
対応概要
対応する際のポイントは下記
- 1, main()で初期値用の一時変数を定義
- 2, main()で初期値取得(Future等)し一時変数に格納
- 3, runApp(ProviderScope()) でProviderに値を設定
実装
・色のThemeと、言語のLanguageを、Providerで管理している場合の例。
(※自身のアプリに組み込む際は、「一時変数定義」「初期値取得処理」「上書き更新」を適宜修正)
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// - 1, main()で初期値用の一時変数を定義 ---
// Future処理後に、値を設定するため late で定義
late final ThemeMode initialLoadedTheme;
late final Language initialLoadedLanguage;
// - 2, main()で初期値取得(Future等)し一時変数に格納 ---
// await Future.wait([])は、複数の非同期処理を並行して実行し、それらが全て完了するのを待つことが可能
// 処理順が関係ない初期値の取得処理をまとめて実行
// また、並列処理なので時間の短縮となる利点がある
await Future.wait(
[
Future(() async {
// MEMO: 起動時に、Themeを取得し、【ProviderScope -> overides で、設定】
initialLoadedTheme = await ThemeSelectorExtension.loadedState();
}),
Future(() async {
// MEMO: 起動時に、言語設定を取得し、【ProviderScope -> overides で、設定】
initialLoadedLanguage = await LaungageSelectorExtension.loadedState();
}),
]
);
}
// - 3, runApp(ProviderScope()) でProviderに値を設定 ---
runApp(
ProviderScope(
overrides: [
// 該当Porviderに、main()で取得した値を設定(override利用)
themeSelectorProvider.overrideWith((ref) => ThemeSelector(initialLoadedTheme),),
languageSelectorProvider.overrideWith((ref) => LanguageSelector(initialLoadedLanguage),),
],
child: MyApp()
)
);
対応コードの解説
- 1, main()で初期値取得し一時変数に格納
- main() -> Future<void> main() async に変更
- final late で、一時変数を用意
- await Future.await([])でFuture処理を実行
※もし、1つしかFuture処理がなくても、今後の追加が楽なので使っておいた方が楽かも
- 2, main()で初期値取得(Future等)し一時変数に格納 ---
- await Future.wait([]) 内で、Future処理を実行しデータ取得
- 3, runApp(ProviderScope()) でProviderに値を設定
- overrider: [] のなかで任意のProviderの初期値を設定
- Provider.overrideWith() で、上書き更新処理で対応
備考
※loadedState()の取得処理の中身は、SharedPreferenceから値を取得している処理です。
/// 現在選択中の言語設定を`SharedPreferences`から取得
Future<Language> loadedState async {
final prefs = await SharedPreferences.getInstance();
final langStr = prefs.getString("languagePrefsKey");
final langEnum = LanguageExtension.whichLanguage(languageStr: langStr ?? "");
return langEnum;
}
注意点
もし初回Futureの処理が重い(長い)場合、「アプリ起動 -> スプラッシュ」の時間が長くなります。
これを嫌う場合は、素直に初回画面起動した後に、「ローディング表示(※)」で対応が良いと思います。
Discussion