【发布时间】:2018-09-26 22:26:00
【问题描述】:
在 Flutter 中,有没有一种方法可以在用户离开应用程序并立即返回时更新小部件?我的应用是基于时间的,尽快更新时间会很有帮助。
【问题讨论】:
在 Flutter 中,有没有一种方法可以在用户离开应用程序并立即返回时更新小部件?我的应用是基于时间的,尽快更新时间会很有帮助。
【问题讨论】:
您可以通过这样做来监听生命周期事件,例如:
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
class LifecycleEventHandler extends WidgetsBindingObserver {
final AsyncCallback resumeCallBack;
final AsyncCallback suspendingCallBack;
LifecycleEventHandler({
this.resumeCallBack,
this.suspendingCallBack,
});
@override
Future<void> didChangeAppLifecycleState(AppLifecycleState state) async {
switch (state) {
case AppLifecycleState.resumed:
if (resumeCallBack != null) {
await resumeCallBack();
}
break;
case AppLifecycleState.inactive:
case AppLifecycleState.paused:
case AppLifecycleState.detached:
if (suspendingCallBack != null) {
await suspendingCallBack();
}
break;
}
}
}
class AppWidgetState extends State<AppWidget> {
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(
LifecycleEventHandler(resumeCallBack: () async => setState(() {
// do something
}))
);
}
...
}
【讨论】:
typedef FutureVoidCallback = Future<void> Function();
使用系统频道:
import 'package:flutter/services.dart';
SystemChannels.lifecycle.setMessageHandler((msg){
debugPrint('SystemChannels> $msg');
if(msg==AppLifecycleState.resumed.toString())setState((){});
});
`
【讨论】:
If you need the binding to be constructed before calling runApp, you can ensure a Widget binding has been constructed by calling the WidgetsFlutterBinding.ensureInitialized() function.
简单的方法:
import 'package:flutter/services.dart';
handleAppLifecycleState() {
AppLifecycleState _lastLifecyleState;
SystemChannels.lifecycle.setMessageHandler((msg) {
print('SystemChannels> $msg');
switch (msg) {
case "AppLifecycleState.paused":
_lastLifecyleState = AppLifecycleState.paused;
break;
case "AppLifecycleState.inactive":
_lastLifecyleState = AppLifecycleState.inactive;
break;
case "AppLifecycleState.resumed":
_lastLifecyleState = AppLifecycleState.resumed;
break;
case "AppLifecycleState.suspending":
_lastLifecyleState = AppLifecycleState.suspending;
break;
default:
}
});
}
只需在您的init() 中添加handleAppLifecycleState()
或
class AppLifecycleReactor extends StatefulWidget {
const AppLifecycleReactor({ Key key }) : super(key: key);
@override
_AppLifecycleReactorState createState() => _AppLifecycleReactorState();
}
class _AppLifecycleReactorState extends State<AppLifecycleReactor> with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
AppLifecycleState _notification;
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
setState(() { _notification = state; });
}
@override
Widget build(BuildContext context) {
return Text('Last notification: $_notification');
}
}
更多详情请参考documentation
【讨论】:
对于深度测试,我认为结果值得一读。如果您对应该使用哪种方法感到好奇,请阅读以下内容:(在 Android 上测试)
LifeCycle 解决方案共有三种方法。
WidgetsBindingObserverSystemChannels.lifecycleWidgetsBindingObserver 和SystemChannels.lifecycle 的主要区别在于WidgetsBindingObserver 有更多的能力如果你有一堆小部件需要监听 LifeCycle。 SystemChannels 是更底层的,由WidgetsBindingObserver 使用。
经过多次测试,如果你在runApp之后使用SystemChannels,并且home widget mixin与WidgetsBindingObserver,home widget会失败,因为SystemChannels.lifecycle.setMessageHandler覆盖了home的方法。
因此,如果您想使用全局、单一的方法,请选择SystemChannels.lifecycle,其他人选择WidgetsBindingObserver。
那么第三种方法呢?这仅适用于 Android,如果您必须在 之前 runApp 绑定您的方法,这是唯一的方法。
【讨论】:
SystemChannels.lifecycle,则不会收到WidgetsBindingObserver 回调。
import 'package:flutter/material.dart';
abstract class LifecycleWatcherState<T extends StatefulWidget> extends State<T>
with WidgetsBindingObserver {
@override
Widget build(BuildContext context) {
return null;
}
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
switch (state) {
case AppLifecycleState.resumed:
onResumed();
break;
case AppLifecycleState.inactive:
onPaused();
break;
case AppLifecycleState.paused:
onInactive();
break;
case AppLifecycleState.detached:
onDetached();
break;
}
}
void onResumed();
void onPaused();
void onInactive();
void onDetached();
}
示例
class ExampleStatefulWidget extends StatefulWidget {
@override
_ExampleStatefulWidgetState createState() => _ExampleStatefulWidgetState();
}
class _ExampleStatefulWidgetState
extends LifecycleWatcherState<ExampleStatefulWidget> {
@override
Widget build(BuildContext context) {
return Container();
}
@override
void onDetached() {
}
@override
void onInactive() {
}
@override
void onPaused() {
}
@override
void onResumed() {
}
}
【讨论】:
下面是一个如何观察包含活动 (Flutter for Android developers) 的生命周期状态的示例:
import 'package:flutter/widgets.dart';
class LifecycleWatcher extends StatefulWidget {
@override
_LifecycleWatcherState createState() => _LifecycleWatcherState();
}
class _LifecycleWatcherState extends State<LifecycleWatcher> with WidgetsBindingObserver {
AppLifecycleState _lastLifecycleState;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
setState(() {
_lastLifecycleState = state;
});
}
@override
Widget build(BuildContext context) {
if (_lastLifecycleState == null)
return Text('This widget has not observed any lifecycle changes.', textDirection: TextDirection.ltr);
return Text('The most recent lifecycle state this widget observed was: $_lastLifecycleState.',
textDirection: TextDirection.ltr);
}
}
void main() {
runApp(Center(child: LifecycleWatcher()));
}
【讨论】:
使用“WidgetsBindingObserver”检测 onResume 事件的解决方案 或“SystemChannels.lifecycle”仅在应用程序完全进入后台时才有效,例如在锁定屏幕事件期间或切换到另一个应用程序期间。如果用户在应用程序的屏幕之间导航,它将不起作用。如果即使在同一应用的不同屏幕之间切换时也想检测 onResume 事件,请从此处使用 visibility_detector 库:https://pub.dev/packages/visibility_detector
@override
Widget build(BuildContext context) {
return VisibilityDetector(
key: Key('my-widget-key'),
onVisibilityChanged: (visibilityInfo) {
num visiblePercentage = visibilityInfo.visibleFraction * 100;
debugPrint(
'Widget ${visibilityInfo.key} is ${visiblePercentage}% visible');
if(visiblePercentage == 100){
debugPrint("Resumed !");
}
},
child: someOtherWidget,
);
}
【讨论】:
如果你想执行 onResume 方法但只在一个页面中,你可以在你的页面中添加这个:
var lifecycleEventHandler;
@override
void initState() {
super.initState();
///To listen onResume method
lifecycleEventHandler = LifecycleEventHandler(
resumeCallBack: () async {
//do something
}
);
WidgetsBinding.instance.addObserver(lifecycleEventHandler);
}
@override
void dispose() {
if(lifecycleEventHandler != null)
WidgetsBinding.instance.removeObserver(lifecycleEventHandler);
super.dispose();
}
并将 LifecycleEventHandler 类作为这篇文章的第一个答案:
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
class LifecycleEventHandler extends WidgetsBindingObserver {
final AsyncCallback resumeCallBack;
final AsyncCallback suspendingCallBack;
LifecycleEventHandler({
this.resumeCallBack,
this.suspendingCallBack,
});
@override
Future<void> didChangeAppLifecycleState(AppLifecycleState state) async {
switch (state) {
case AppLifecycleState.resumed:
if (resumeCallBack != null) {
await resumeCallBack();
}
break;
case AppLifecycleState.inactive:
case AppLifecycleState.paused:
case AppLifecycleState.detached:
if (suspendingCallBack != null) {
await suspendingCallBack();
}
break;
}
}
}
【讨论】: