アプリを開発しているとアプリの初回起動時に初期化処理をしたいというユースケースが頻繁にあると思います。
ネイティブの開発ではSharedPreferencesやUserDefaultsで起動するActivityやUIViewControllerを切り替える方法をとってきました。
Flutterも同じ方法でやろうとしたところ、FlutterのSharedPreferencesはインスタンスの取得が非同期だったので、一工夫必要でした。
build
関数の戻り値を直接Widgetにするのでなく、FutureBuilder
でラップすることで非同期コードの結果に応じて、使用するWidgetを切り替えることが可能です。
ただし注意点として非同期コードの結果が取得される前の状態(hasData==null
)の場合のWidgetも返却する必要があります。
アプリ初期化のユースケースを例にしたサンプルコードは次のようになります。
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:shared_preferences/shared_preferences.dart';
class App extends StatefulWidget {
@override
State createState() => new AppState();
}
class AppState extends State<App> {
Future<bool>getIsInitialized() async{
final sharedPreferences = await SharedPreferences.getInstance();
bool isInitialized = sharedPreferences.getBool("isInitialized");
if (isInitialized == null) {
print("isInitialized is null");
isInitialized = false;
}
return isInitialized;
}
@override
Widget build(BuildContext context) {
// FutureBuilderでラップする
return new FutureBuilder(
future: getIsInitialized(),
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
print(snapshot);
// hasData==nullの場合とはgetIsInitializedのレスポンスを取得できる状態になる前
// この場合もWidgetの返却がひつようなので、とりあえずインジケーターを設定しておく
final hasData = snapshot.hasData;
print("hasData:$hasData");
if (hasData == false) {
return CircularProgressIndicator();
}
// アプリの初期化状態を取得
final isInitialized = snapshot.data;
print("isInitialized:$isInitialized");
var homeWidget;
if (isInitialized) {
homeWidget = MainScreenWidget(); // 初期化済みならメインスクリーンを表示
} else {
homeWidget = InitializeScreenWidget(); // 初期化スクリーンを表示
}
var app = new MaterialApp(
title: "Couple Todo",
home: homeWidget,
);
return app;
});
}
}