起動しているアプリがバックグラウンド実行になった時、またはアクティブ状態に再開した等を検知して何か処理を実行したいことがあります。
そういったアプリのライフサイクルは、Flutterでは enum AppLifecycleState
として定義されています。
enum AppLifecycleState {
resumed,
inactive,
paused,
detached,
}
これらのライフサイクル変更をRiverpodのProviderを使用して監視できるようにしましょう👍
全体の実装コードは以下のサンプルリポジトリの該当ファイルで確認できます↓
それでは、以下で1つずつ説明していきます。
Observerクラスを定義
まずは、 WidgetsBindingObserver
を継承したクラスを作成します。
class _AppLifecycleObserver extends WidgetsBindingObserver {
_AppLifecycleObserver(this._didChangeState);
final ValueChanged<AppLifecycleState> _didChangeState;
void didChangeAppLifecycleState(AppLifecycleState state) {
_didChangeState(state);
super.didChangeAppLifecycleState(state);
}
}
ここでは _AppLifecycleObserver
という名前にしました。
外部から処理を追加できるように(コールバックを渡せるように)、 _didChangeState
というプロパティを定義してコンストラクタで処理を渡せるようにしておきます。
WidgetsBindingObserver
は didChangeAppLifecycleState
というメソッドを持つのでこれをオーバーライドしましょう。
このメソッドの引数で AppLifecycleState
、すなわちアプリのライフサイクル状態を取得できます。
ここで _didChangeState
メソッドに AppLifecycleState state
を渡します。
super
を使って継承元の didChangeAppLifecycleState
メソッドも実行しておきましょう。
Providerを作成
Riverpodのプロバイダを通じて _AppLifecycleObserver
を使用するためにProviderを定義します。
まず _AppLifecycleObserver
をインスタンス化して observer
という名前で受け取りましょう。
この時、 _didChangeState
で実行される処理を渡しています。
value
(AppLifecycleState) を受け取ったら ref.state = value
で自信の値を変更しています。
WidgetsBinding.instance..addObserver
で observer
を登録。
ref.onDispose
で、Providerが破棄されたときに observer
を解除しています。
最後に、初期値として AppLifecycleState.resumed
を返しています。
final appLifecycleProvider = Provider<AppLifecycleState>((ref) {
final observer = _AppLifecycleObserver((value) => ref.state = value);
final binding = WidgetsBinding.instance..addObserver(observer);
ref.onDispose(() => binding.removeObserver(observer));
return AppLifecycleState.resumed;
});
Widgetからの使用例
ref.listen
を使用してアプリのライフサイクルを検知する例です。
ref
が使用できる箇所であれば同じようにどこでも監視可能ですし、リビルドさせたい場合は ref.watch
でも使用できます。
行いたい処理の責務にあった箇所でプロバイダを購読してライフサイクルを取得しましょう。
class App extends ConsumerWidget {
const App({
super.key,
});
Widget build(BuildContext context, WidgetRef ref) {
// appLifecycleProviderの状態変更を監視
ref.listen<AppLifecycleState>(
appLifecycleProvider,
// `next` に変更された `AppLifecycleState` が入ってきます。
// 任意の処理を行いましょう。
(previous, next) => debugPrint('Previous: $previous, Next: $next'),
);
return const SplashPage();
}
}
参考元
Riverpod作者であるRemiさんのこちらのツイート内コードを参考にさせていただきました。