FlutterアプリでonResume的なタイミングの処理をする/複数ウィジェットで監視編

Flutterアプリで、Androidでいう`onResume`のタイミング(アプリがホームボタンなどでバックグラウンドに行ってまた前面に戻ったとき)で処理をしたいと思い、以下の記事を書きました。

FlutterアプリでonResume的なタイミングの処理をする
https://qiita.com/kasa_le/items/1fdbe07112ab4aed250a

しかし、複数のウィジェットで同時多発的に監視したいときに、この方法では問題がありました。
関数名を見て貰えれば分かりますが、`set***`なので、**最後にセットしたコールバックしか呼ばれません。**

ということで、対処法を調べたのでそのまとめです。

# 環境など

|ツールなど|バージョンなど|
|:--|:--|
| MacBook Air Early2015|macOS Mojave 10.14.6|
|Android Studio |3.6.1|
|Java |1.8.0_131|
|Flutter|1.12.13+hotfix.9|
|Dart |2.7.2|
|Xcode |11.3.1|

# 解決策

`WidgetsBindingObserver`を使います。

## 1.StatefulWidgetで使う
基本的に、`WidgetsBindingObserver`は`StatefulWidget`でなければ使えません。

```dart
class SomeWidget extends StatefulWidget {
 @override
  State<StatefulWidget> createState() => _SomeState();
}

class _SomeState extends State<SomeWidget> with WidgetsBindingObserver {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      // onResume処理
    }
  }

  @override
  Widget build(BuildContext context) {
     return ...
  }
}
```

だいたいこんな感じで使えます。

## 2.LifecycleManagerクラスを作る
よくあるコールバック方式で、こんな方法も出来ます。

```LifecycleManager.dart
/// ライフサイクルコールバックインターフェース
class LifecycleCallback {
  void onResumed() {}

  void onPaused() {}

  void onInactive() {}

  void onDetached() {}
}

/// ライフサイクルを受け取れるStatefulWidget
class LifecycleManager extends StatefulWidget {
  final Widget child;
  final LifecycleCallback callback;

  LifecycleManager({Key key, this.child, this.callback}) : super(key: key);

  _LifeCycleManagerState createState() => _LifeCycleManagerState();
}

class _LifeCycleManagerState extends State<LifecycleManager>
    with WidgetsBindingObserver {
  @override
  void initState() {
    WidgetsBinding.instance.addObserver(this);
    super.initState();
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    print('state = $state');
    switch (state) {
      case AppLifecycleState.resumed:
        widget.callback?.onResumed();
        break;
      case AppLifecycleState.inactive:
        widget.callback?.onInactive();
        break;
      case AppLifecycleState.paused:
        widget.callback?.onPaused();
        break;
      case AppLifecycleState.detached:
        widget.callback?.onDetached();
        break;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: widget.child,
    );
  }
}
```

で、`StatelessWidget#build`などでこう返します。

```dart
   return LifecycleManager(
      callback: _onLifecycleCallback,
      child: MyWidget(),
   );
```

基本的に`StatelessWidget`で作っていたりすると、`onResume`処理が必要なウィジェットだけ`StatetulWidget`に変えていくのも結構面倒だったりします。そこで、この`LifecycleManager`で「括ってしまえば」ちょっとは楽かと思います。


# 参考サイト
https://stackoverflow.com/questions/49869873/flutter-update-widgets-on-resume
https://medium.com/flutter-community/build-a-lifecycle-manager-to-manage-your-services-b9c928d3aed7