Flutterアプリのフォアグラウンド/バックグラウンド時のイベントを整理したが、detachedだけでない件

---
# :book: Flutterの記事を整理し本にしました :book:
https://zenn.dev/kazutxt/books/flutter_practice_introduction

* <font color="red"><b>本稿の記事を含む様々な記事を体系的に整理し本にまとめました</b></font>
* 今後はこちらを最新化するため、<font color="red"><b>最新情報はこちらをご確認くださ</b>い</font>
* 10万文字を超える超大作になっています(笑)

---

# はじめに
* アプリの一時停止や復旧のアプリライフサイクルイベントを整理しました

## まとめ
* [Flutter系の記事のまとめ](https://qiita.com/kazutxt/items/524acb1c134015682ccf)


# アプリライフサイクルとは

アプリは常にフォアグラウンドで画面に表示され、ユーザからの操作を受け付けているわけではありません。
別のアプリが割り込んだり、ユーザ操作でバックグラウンドに移されることがあります。
この一時停止や復旧に対応した処理を準備しておくことで、ユーザのUX改善につながる場合があります。

# ソースコード

```dart:main.dart
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() {
  runApp(MyApp());
}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}
class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;
  @override
  _MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance!.addObserver(this);
  }
  @override
  void dispose() {
    print("dispose");
    WidgetsBinding.instance!.removeObserver(this);
    super.dispose();
  }
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    print("stete = $state");
    switch (state) {
      case AppLifecycleState.inactive:
        print('非アクティブになったときの処理');
        break;
      case AppLifecycleState.paused:
        print('停止されたときの処理');
        break;
      case AppLifecycleState.resumed:
        print('再開されたときの処理');
        break;
      case AppLifecycleState.detached:
        print('破棄されたときの処理');
        break;
    }
  }
  int _counter = 0;
  _incrementCounter() {
    setState(() {
      _counter++;
    });
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}
```
`with WidgetsBindingObserver`でミックスインをすることでアプリライフサイクルの管理が可能です。
`didChangeAppLifecycleState`が状態の変更があった時に呼び出されるメソッドです。

状態は以下の4つが定義されています。

* inactive
  * 非アクティブになった時
* paused
  * バックグラウンドになった時
* resumed
  * フォアグラウンドに再開された時
* detached:
  * アプリが破棄された時

どの状態がどのタイミングで呼ばれるかは、機器やAndroid/iOSによって差があります。
詳細は、[AppLifecycleState](https://api.flutter.dev/flutter/dart-ui/AppLifecycleState-class.html)の公式ドキュメントでご確認ください

# 動作確認
ホームボタン等をおして、バックグラウンドとフォアグラウンドを入れ替えると、コンソールにメッセージがでます。

![pic11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259228/0249a3a1-7c99-2a93-0289-e140d10a6c61.png)


バックグラウンドに移したときの表示

```sh:result.sh
I/flutter ( 5955): stete = AppLifecycleState.inactive
I/flutter ( 5955): 非アクティブになったときの処理
I/flutter ( 5955): stete = AppLifecycleState.paused
I/flutter ( 5955): 停止されたときの処理
```

フォアグラウンドに移したときの表示

```sh:result.sh
I/flutter ( 5955): stete = AppLifecycleState.resumed
I/flutter ( 5955): 再開されたときの処理
```

前述の通り、どの状態のイベントが呼ばれるかは機器やOSによって異なります。
detachedがアプリが終了した時に呼び出されるとされていますが、本チャプター執筆時に検証したエミュレータや実機では表示させることができませんでした。

ネットでもでないという記事をちらほら見かけますが、困ったな。。。