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でなければ使えません。
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クラスを作る
よくあるコールバック方式で、こんな方法も出来ます。
/// ライフサイクルコールバックインターフェース
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などでこう返します。
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