[Flutter/Dart]アプリの状態変化(バックグラウンド/フォアグラウンド)を監視・取得する方法

2020年11月16日(更新: 2020年11月30日)

別のアプリを起動したり端末をスリープさせたりすることでアプリがバックグラウンド状態になる際、何かしらの処理を行わせたいという場合があります。

Flutter では、状態を監視させたい Widget に WidgetsBindingObserver を設定すると、その中のメソッド didChangeAppLifecycleState でアプリの状態が変化した際に AppLifecycleState を受け取ることができます。

取得できるアプリの状態変化

取得できるアプリの状態変化には下記の5種類がありますが、端末のOSの種類(Android/iOS)によって受け取れる状態が若干異なるようです。以下のページを参考に、状態についてまとめてみます。

  1. How do I listen to iOS lifecycle events?
  2. How do I listen to Android activity lifecycle events?
  3. AppLifecycleState enum – dart:ui library – Dart API

detached

Flutterエンジン上で動作していながらもビューが無い状態。エンジンの初期起動時や Navigator.pop によってビューが破棄された際になるとのことです。

実際にテストしてみたところ、Android ではバックボタンでアプリからホーム画面に戻った際にこの状態になっていました。

inactive

ユーザーからの入力を受け取らない非アクティブ状態。

iOSでは、例えば、着信があった際やTouchIDの要求画面の表示、コントロールセンターを開いた時、UIViewControllerのトランジション時など。

Android では相当するイベントが無いとされていますが「参考3」には以下のような記述があります。

On Android, this corresponds to an app or the Flutter host view running in the foreground inactive state. Apps transition to this state when another activity is focused, such as a split-screen app, a phone call, a picture-in-picture app, a system dialog, or another window.

Android でもトランジションによって他のアクティビティがアクティブになったり、着信やピクチャ・イン・ピクチャの動画アプリのようなもの、システムダイアログなどによって inactive 状態になるようです。

実際に Android の実機でテストしてみると、バックグラウンドアプリ一覧画面を開いたとき(pixelでは画面下からの上方向スワイプ)に inactive の状態となっていました。iOSではホーム画面に戻る際やバックグラウンドアプリ一覧画面を開く時の他に、paused から resumed に移行する間にこの状態となっていました。

この状態のアプリは、いつでも pause 状態に移行する可能性があるとみなされます。実際のテストでも inactive となった後に pause となることが多かったです。

paused

アプリがユーザーに非表示であり入力も受け付けず、バックグラウンドで動作している状態。Android における onPause() に相当。

この状態の時、コールバック Window.onBeginFrame および Window.onDrawFrame は呼ばれないとのこと。

実機では完全にホーム画面に戻った時に paused となります。

resume

アプリがフォアグラウンドに移行した時。

アプリは可視状態となり、入力も受け取るようになる。Android における onPostResume() に相当。

suspending(Androidのみ)

アプリの一時停止状態。Android における onStop() に相当。iOSには相当するイベントは存在しない。

サンプル

「参考2」のサンプルコードを参考にした、アプリ状態を確認できる StatefulWidget のサンプルです。コンソールにログを残すように変更を加えています。

import 'dart:developer';

...(mainなどは省略)...

class Test extends StatefulWidget {
  @override
  _TestState createState() => _TestState();
}

class _TestState extends State<Test> with WidgetsBindingObserver {
  
  AppLifecycleState _state;

  @override
  void initState() {
    super.initState();
    // 状態監視を開始
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    // 状態監視のオブザーバーを破棄
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    
    log('state: $state');
    
    setState(() {
      // 状態変化を変数に格納
      _state = state;
    });
  }

  @override
  Widget build(BuildContext context) {

    if (_state == null) {
      return Text('');
    }
    return Text('$_state');
  }
}

ログに状態の変化が記録されます。

AppLifecycleStateの変化ログ

以上、Flutter でアプリの状態変化を取得する方法についてでした。

コメントを残す

メールアドレスが公開されることはありません。