person t-kobayashi

Flutter WidgetsBindingObserverを使ってiOSとAndroidのアプリの挙動を確認してみる

calendar_today 2021年07月21日 update 2021年07月21日
Facebook Twitter LINE はてなブックマーク Pocket

Flutter 2.2.0から2.2.3にアップグレードをしたところ、エラーなしでできました。

今日は、FlutterのWidgetsBindingObserverを使って、ライフサイクルステートで、どのコードが実行されているのかログを使って確認していきたいと思います。

WidgetsBindingObserverの設定

まず、下記のコマンドで新規のFlutterアプリを作成します。

flutter create lifecycle_observer

lib/main.dartにて、下記のクラスを定義します。

class _StateHandler extends WidgetsBindingObserver {
  
}

上記のクラスのdidChangeAppLifecycleState(AppLifecycleState state)メソッドをオーバーライドして、下記のように定義します。

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    switch (state) {
      case AppLifecycleState.resumed:
        print("Resumed and Foreground Active in iOS, resumed in Android...");
        break;
      case AppLifecycleState.paused:
        print("Paused and Background in iOS, created in Android...");
        break;
      case AppLifecycleState.inactive:
        print("Inactive and Foreground Inactive in iOS, started in Android...");
        break;
      case AppLifecycleState.detached:
        print(
            "Detached and Unattached or Suspended in iOS, initialized or destroyed in Android...");
        break;
      default:
        print("Unknown State");
    }
  }

このコードはアプリのライフサイクルステートに変更があった場合に実行されます。Flutterアプリのライフサイクルステートは4つ定義されており、それぞれのステートに変化した際に、print関数を使って、ログに出力します。

次にmain()関数に以下のようにコードを追加して、上記で定義したクラスをオブザーバーとして追加します。

void main() {
  runApp(MyApp());
  WidgetsBinding.instance!.addObserver(new _StateHandler());
}

iOSでの挙動を確認

それでは、早速起動してみます。iOSシミュレータを起動した状態で下記のコマンドを実行します。

flutter run

通常のログの中に、下記の文字列が出力されていることがわかります。

flutter: Resumed and Foreground Active in iOS, resumed in Android...

この文字列は、ライフサイクルステートがresumedのとき、つまりアプリが操作可能な状態になった時点で出力されています。

iPhone 11 Proのシミュレータを利用しているので、画面下部にマウスをあてて、少しドラッグアップすると、今度は下記の文字列が出力されます。

flutter: Inactive and Foreground Inactive in iOS, started in Android...

アプリは画面上に見えているが操作できない状態、つまりライフサイクルステートがinactiveの状態に変化したというです。

再び、操作できる状態に戻すと、resumedにステートが変わったことを示すメッセージが出力されます。

電源ボタンなどを押して、アプリを画面から消すと下記の文字列が表示され、ライフサイクルステートがpausedに移行したことがわかります。

flutter: Paused and Background in iOS, created in Android...

そこから、もう一度アプリを表示させると、今度は以下のように文字列が出力されます。

flutter: Inactive and Foreground Inactive in iOS, started in Android...
flutter: Resumed and Foreground Active in iOS, resumed in Android...

これは、ライフサイクルステートが、pausedからinactive、そしてresumedへと順番に変化していることを示しています。

detachedステートで表示されるはずの文字列は確認できませんでした。これは当然と言えば当然ですが、detachedのステートにあるということはすでにアプリは動作していない状態だと考えられるので、文字列の出力自体がされないため、見ることができないということですね。

Androidでの挙動を確認

今度はAndroidのエミュレータで同様の操作をしてみます。Androidエミュレータを起動した状態で、flutter runを実行します。しかし、起動はするのですが、Resumed and Foreground Active in iOS, resumed in Android...という文字列は表示されません。

エミュレータの「Overview」ボタンを押して、画面上に見えているが操作できないinactiveの状態にしてみます。すると下記の文字列が出力されます。

I/flutter ( 4654): Inactive and Foreground Inactive in iOS, started in Android...
I/flutter ( 4654): Paused and Background in iOS, created in Android...

この時点で、バックグラウンドの状態にまで進んでいるのがわかります。iOSの時と挙動がかなり異なることがわかります。

操作できる状態にアプリを戻すと、下記の文字列が表示されます。

I/flutter ( 4654): Resumed and Foreground Active in iOS, resumed in Android...

ここは想定内ですね。ここで電源ボタンを押してアプリを画面から消してみると、下記の文字列が再び表示されます。

I/flutter ( 4654): Inactive and Foreground Inactive in iOS, started in Android...
I/flutter ( 4654): Paused and Background in iOS, created in Android...

これも想定通りです。

ここから電源を入れて、再び操作できる状態に戻すと下記の文字列のみが出力されました。

I/flutter ( 4654): Resumed and Foreground Active in iOS, resumed in Android...

これは意外です。inactive状態を経由せずにresumed状態になっています。

detachedのメッセージはAndroidでも表示させることはできませんでした。

まとめ

これまでにも、AndroidとiOSのアプリには起動時の挙動が異なるということを経験したことがあったのですが、今回の検証でその理由が分かったような気がします。意外だったのは、Androidで起動した際のステート遷移の特徴でした。Kotlinでアクティビティのステート遷移を類似の方法で確認した時は、わかりやすいと感じたのですが、FlutterアプリのAndroid上でのライフサイクルには挙動にクセがあるように感じます。

参考サイト:

https://api.flutter.dev/flutter/widgets/WidgetsBindingObserver-class.html

関連記事

Flutterの記事一覧を見る

Flutterの質問

soichiro1210 が1年前に投稿

質問日時 2023年07月31日

a-sato が3年前に投稿

質問日時 2021年07月01日

a-sato が3年前に投稿

質問日時 2021年06月30日

takumi が3年前に投稿

質問日時 2021年05月20日

a-sato が3年前に投稿

質問日時 2021年05月14日

Flutterの質問一覧を見る
search