Flutter 上的小部件的 onResume() 和 onPause()
Posted
技术标签:
【中文标题】Flutter 上的小部件的 onResume() 和 onPause()【英文标题】:onResume() and onPause() for widgets on Flutter 【发布时间】:2017-11-04 00:43:25 【问题描述】:现在,一个小部件只有在第一次创建小部件时触发的 initeState() 和在销毁小部件时触发的 dispose()。有没有一种方法可以检测小部件何时回到前台?当一个小部件因为另一个小部件刚刚被前景化而即将进入后台时? 相当于 android 触发 onResume 和 onPause 触发 ios 触发 viewWillAppear 和 viewWillDisappear
【问题讨论】:
您的用例是什么?了解您正在尝试做什么可以帮助我们提供更多信息。谢谢! 答案太棒了!但我所寻找的正是***.com/a/44417260/3217522 看看 FocusDetector。它正在监听小部件的前台可见性:pub.dev/packages/focus_detector 【参考方案1】:有一个抽象类调用者WidgetsBindingObserver
https://docs.flutter.io/flutter/widgets/WidgetsBindingObserver-class.html
在
@override
void didChangeAppLifecycleState(AppLifecycleState state)
setState(()
_notification = state;
);
有“状态”,可以管理为
switch(state)
case AppLifecycleState.resumed:
// Handle this case
break;
case AppLifecycleState.inactive:
// Handle this case
break;
case AppLifecycleState.paused:
// Handle this case
break;
case AppLifecycleState.suspending:
// Handle this case
break;
【讨论】:
我试过了,但从未调用过 didChangeAppLifecycleState()。我还能做什么? 你添加了“with WidgetsBindingObserver”吗?请参阅docs.flutter.io/flutter/widgets/… 的文档 谢谢。后来我意识到生命周期是如何工作的。它并不是为了解决我想要解决的问题。我找到了另一种解决问题的方法。 这是应用程序级别的生命周期,这意味着,当整体恢复或不活动或暂停时,而不是单个小部件。 这是应用程序生命周期,而不是小部件生命周期【参考方案2】:这是一个完整的例子,展示了如何正确处理事情,为了测试这个,按下主页按钮并恢复应用程序,你会看到didChangeAppLifecycleState
被调用。
class HomePage extends StatefulWidget
@override
_HomePageState createState() => _HomePageState();
class _HomePageState extends State<HomePage> with WidgetsBindingObserver
@override
void initState()
super.initState();
// Add the observer.
WidgetsBinding.instance!.addObserver(this);
@override
void dispose()
// Remove the observer
WidgetsBinding.instance!.removeObserver(this);
super.dispose();
@override
void didChangeAppLifecycleState(AppLifecycleState state)
super.didChangeAppLifecycleState(state);
// These are the callbacks
switch (state)
case AppLifecycleState.resumed:
// widget is resumed
break;
case AppLifecycleState.inactive:
// widget is inactive
break;
case AppLifecycleState.paused:
// widget is paused
break;
case AppLifecycleState.detached:
// widget is detached
break;
@override
Widget build(BuildContext context) => Scaffold();
【讨论】:
太棒了!这一定是公认的答案! 实际上这段代码 sn -p 监控的是应用程序的生命周期,而不是小部件。如果你测试它,你会发现简历上的“第一个”没有被调用。这是因为应用程序已经恢复。需要为 Android 片段/活动等效项找到另一个解决方案:)【参考方案3】:您想要执行此操作的最常见情况是,如果您正在运行动画并且您不想在后台消耗资源。在这种情况下,您应该使用TickerProviderStateMixin
扩展您的State
,并使用您的State
作为vsync
的AnimationController
参数。 Flutter 只会在你的 State
可见时调用动画控制器的监听器。
如果您希望在 PageRoute
被其他内容遮盖时处置存在于您的 PageRoute
中的 State
s,您可以将 false
的 maintainState
参数传递给您的 PageRoute
构造函数.如果您这样做,您的State
将在隐藏时重置自身(及其子级),并且必须使用作为构造函数参数传递给其widget
的属性在initState
中重新构建自身。如果您不想完全重置,可以使用模型或控制器类或PageStorage
来保存用户的进度信息。
这是一个演示这些概念的示例应用程序。
import 'package:flutter/material.dart';
void main()
runApp(new MaterialApp(
onGenerateRoute: (RouteSettings settings)
if (settings.name == '/')
return new MaterialPageRoute<Null>(
settings: settings,
builder: (_) => new MyApp(),
maintainState: false,
);
return null;
));
class MyApp extends StatefulWidget
MyAppState createState() => new MyAppState();
class MyAppState extends State<MyApp> with TickerProviderStateMixin
AnimationController _controller;
@override
void initState()
print("initState was called");
_controller = new AnimationController(vsync: this)
..repeat(min: 0.0, max: 1.0, period: const Duration(seconds: 1))
..addListener(()
print('animation value $_controller.value');
);
super.initState();
@override
void dispose()
print("dispose was called");
_controller.dispose();
super.dispose();
int _counter = 0;
@override
Widget build(BuildContext context)
return new Scaffold(
appBar: new AppBar(
title: new Text('home screen')
),
body: new Center(
child: new RaisedButton(
onPressed: ()
setState(()
_counter++;
);
,
child: new Text('Button pressed $_counter times'),
),
),
floatingActionButton: new FloatingActionButton(
child: new Icon(Icons.remove_red_eye),
onPressed: ()
Navigator.push(context, new MaterialPageRoute(
builder: (BuildContext context)
return new MySecondPage(counter: _counter);
,
));
,
),
);
class MySecondPage extends StatelessWidget
MySecondPage( this.counter );
final int counter;
Widget build(BuildContext context)
return new Scaffold(
appBar: new AppBar(
title: new Text('Certificate of achievement'),
),
body: new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
new Icon(Icons.developer_mode, size: 200.0),
new Text(
'Congrats, you clicked $counter times.',
style: Theme.of(context).textTheme.title,
textAlign: TextAlign.center,
),
new Text(
'All your progress has now been lost.',
style: Theme.of(context).textTheme.subhead,
textAlign: TextAlign.center,
),
],
),
);
【讨论】:
如果它只是您想要处理/重新创建的选项卡控制器的一个选项卡怎么办?而且您不想弄乱保存/恢复会很痛苦的其他选项卡?【参考方案4】:我有点晚了,但为将来可能正在寻找它的人提供了完美的解决方案。 Navigator.push()
实际上是一个未来。这意味着它具有then()
回调函数。因此,在您从第二个屏幕调用 Navigator.pop()
之后,将调用 then()
。甚至您可以从第二个屏幕发送一些数据并访问第一个屏幕中的数据。
示例:
//from Screen A
Navigator.of(context).push(MaterialPageRoute(builder:(context)=>B()))
.then((value)=> refresh() );
//in Screen B with data
Navigator.pop(context,[1]);
//or without data
Navigator.pop(context);
所以refresh()
将在屏幕 A 的简历上被调用。
【讨论】:
如果屏幕 B 没有Navigator.pop(context,[1]);
怎么办。所以屏幕 A 上的then
永远不会运行。【参考方案5】:
我创建 visibility_aware_state 是因为它的行为类似于 Android 的 Activity.onResume()
。它还考虑了弹出和推送导航。
class Example extends StatefulWidget
@override
_ExampleState createState() => _ExampleState();
class _ExampleState extends VisibilityAwareState<Example>
@override
Widget build(BuildContext context)
// return your widget
@override
void onVisibilityChanged(WidgetVisibility visibility)
switch(visibility)
case WidgetVisibility.VISIBLE:
// Like Android's Activity.onResume()
break;
case WidgetVisibility.INVISIBLE:
// Like Android's Activity.onPause()
break;
case WidgetVisibility.GONE:
// Like Android's Activity.onDestroy()
break;
super.onVisibilityChanged(visibility);
【讨论】:
很好,感谢您构建和分享此解决方案。我有一个基类设置,WidgetsBindingObserver
和 @override
的解决方案 void didChangeAppLifecycleState(AppLifecycleState state)
在那里不起作用。这在该设置中确实有效【参考方案6】:
Mamnarock您的回答正确但不完整,您分享的链接不可用。
完整代码如下:
import 'package:flutter/material.dart';
class YourClass extends StatefulWidget
@override
_YourClassState createState() => _YourClassState();
class _YourClassState extends State<YourClass>
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)
switch (state)
case AppLifecycleState.resumed:
// Handle this case
break;
case AppLifecycleState.inactive:
// Handle this case
break;
case AppLifecycleState.paused:
// Handle this case
break;
case AppLifecycleState.detached:
// Handle this case
break;
@override
Widget build(BuildContext context)
return Container();
正如评论中提到的 TeeTracker:
这是一个应用级别的生命周期,这意味着当整体恢复、不活动或暂停时,而不是单个小部件。
【讨论】:
以上是关于Flutter 上的小部件的 onResume() 和 onPause()的主要内容,如果未能解决你的问题,请参考以下文章
Flutter:StreamProvider 的奇怪行为,使用不完整数据重建的小部件