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