简短回答:不,这是不可能的,尽管我观察到显示器进入睡眠状态时会出现不同的行为。以下代码将帮助您了解 Android 上 Flutter 应用的不同状态,并使用这些 Flutter 和 Flutter Engine 版本进行测试:
- 框架修订 b339c71523(6 小时前),2017-02-04 00:51:32
- 引擎修订版 cd34b0ef39
新建一个 Flutter 应用,将lib/main.dart 的内容替换成这段代码:
import 'dart:async';
import 'package:flutter/material.dart';
void main() {
runApp(new MyApp());
}
class LifecycleWatcher extends StatefulWidget {
@override
_LifecycleWatcherState createState() => new _LifecycleWatcherState();
}
class _LifecycleWatcherState extends State<LifecycleWatcher>
with WidgetsBindingObserver {
AppLifecycleState _lastLifecyleState;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void onDeactivate() {
super.deactivate();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
print("LifecycleWatcherState#didChangeAppLifecycleState state=${state.toString()}");
setState(() {
_lastLifecyleState = state;
});
}
@override
Widget build(BuildContext context) {
if (_lastLifecyleState == null)
return new Text('This widget has not observed any lifecycle changes.');
return new Text(
'The most recent lifecycle state this widget observed was: $_lastLifecyleState.');
}
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter App Lifecycle'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _timerCounter = 0;
// ignore: unused_field only created once
Timer _timer;
_MyHomePageState() {
print("_MyHomePageState#constructor, creating new Timer.periodic");
_timer = new Timer.periodic(
new Duration(milliseconds: 3000), _incrementTimerCounter);
}
void _incrementTimerCounter(Timer t) {
print("_timerCounter is $_timerCounter");
setState(() {
_timerCounter++;
});
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(config.title),
),
body: new Block(
children: [
new Text(
'Timer called $_timerCounter time${ _timerCounter == 1 ? '' : 's' }.',
),
new LifecycleWatcher(),
],
),
);
}
}
启动应用时,_timerCounter 的值每 3 秒递增一次。计数器下方的文本字段将显示 Flutter 应用的任何 AppLifecycleState 更改,您将在 Flutter 调试日志中看到相应的输出,例如:
[raju@eagle:~/flutter/helloworld]$ flutter run
Launching lib/main.dart on SM N920S in debug mode...
Building APK in debug mode (android-arm)... 6440ms
Installing build/app.apk... 6496ms
I/flutter (28196): _MyHomePageState#constructor, creating new Timer.periodic
Syncing files to device...
I/flutter (28196): _timerCounter is 0
? To hot reload your app on the fly, press "r" or F5. To restart the app entirely, press "R".
The Observatory debugger and profiler is available at: http://127.0.0.1:8108/
For a more detailed help message, press "h" or F1. To quit, press "q", F10, or Ctrl-C.
I/flutter (28196): _timerCounter is 1
I/flutter (28196): LifecycleWatcherState#didChangeAppLifecycleState state=AppLifecycleState.paused
I/flutter (28196): _timerCounter is 2
I/flutter (28196): _timerCounter is 3
I/flutter (28196): LifecycleWatcherState#didChangeAppLifecycleState state=AppLifecycleState.resumed
I/flutter (28196): _timerCounter is 4
I/flutter (28196): LifecycleWatcherState#didChangeAppLifecycleState state=AppLifecycleState.paused
I/flutter (28196): _timerCounter is 5
I/flutter (28196): _timerCounter is 6
I/flutter (28196): _timerCounter is 7
I/flutter (28196): LifecycleWatcherState#didChangeAppLifecycleState state=AppLifecycleState.resumed
I/flutter (28196): LifecycleWatcherState#didChangeAppLifecycleState state=AppLifecycleState.paused
I/flutter (28196): _timerCounter is 8
I/flutter (28196): _MyHomePageState#constructor, creating new Timer.periodic
I/flutter (28196): _timerCounter is 0
I/flutter (28196): _timerCounter is 1
对于上面的日志输出,下面是我做的步骤:
- 使用
flutter run 启动应用程序
- 切换到其他应用(_timerCounter 值为 1)
- 返回 Flutter 应用(_timerCounter 值为 3)
- 按下电源按钮,显示屏关闭(_timerCounter 值 4)
- 手机解锁,Flutter 应用恢复(_timerCounter 值为 7)
- 按下手机上的返回按钮(_timerCounter 值未更改)。这是 FlutterActivity 和 Dart VM Isolate 被破坏的时刻。
- Flutter 应用恢复(_timerCounter 值再次为 0)
在应用之间切换,按电源或返回按钮
当切换到另一个应用程序时,或者当按下电源按钮关闭屏幕时,计时器会继续运行。但是当 Flutter 应用程序获得焦点时按下后退按钮时,Activity 会被销毁,Dart 也会随之被隔离。您可以通过在应用程序之间切换或转动屏幕时连接到Dart Observatory 来进行测试。 Observatory 将显示一个活动的 Flutter 应用程序 Isolate 正在运行。但是当按下返回按钮时,天文台显示没有运行隔离。该行为已在运行 Android 6.x 的 Galaxy Note 5 和运行 Android 4.4.x 的 Nexus 4 上得到确认。
Flutter 应用生命周期和 Android 生命周期
对于 Flutter 小部件层,仅暴露了 paused 和 resumed 状态。 Android Flutter 应用的销毁由 Android Activity 处理:
/**
* @see android.app.Activity#onDestroy()
*/
@Override
protected void onDestroy() {
if (flutterView != null) {
flutterView.destroy();
}
super.onDestroy();
}
由于 Flutter 应用的 Dart VM 在 Activity 中运行,因此每次 Activity 被销毁时 VM 都会停止。
Flutter Engine 代码逻辑
这不会直接回答您的问题,但会为您提供有关 Flutter 引擎如何处理 Android 状态更改的一些更详细的背景信息。
查看 Flutter 引擎代码很明显,当FlutterActivity 收到 Android 的Activity#onPause 事件时,动画循环会暂停。当应用程序进入 paused 状态时,根据source comment here 会发生以下情况:
“应用当前对用户不可见。当应用处于此状态时,引擎不会调用[onBeginFrame]回调。”
根据我的测试,即使 UI 渲染暂停,计时器也会继续工作,这是有道理的。当 Activity 被销毁时,最好使用 WidgetsBindingObserver 将事件发送到小部件层,这样开发人员可以确保在 Activity 恢复之前存储 Flutter 应用的状态。