Reputation: 302
I’ve got a StatefulWidget
in my Flutter app. The StatefulWidget
has the following property set:
final pausedTimeAllowed = 0;
Here’s my implementation of didChangeAppLifecycleState
within the State
class for that widget:
@override void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
if (!(ModalRoute.of(context)!.isCurrent)) {
return;
}
switch (state) {
case AppLifecycleState.resumed:
debugPrint("didChangeAppLifecycleState: resumed");
if ((globals.pausedSince is DateTime) && (DateTime.now().difference(globals.pausedSince).inSeconds > widget.pausedTimeAllowed)) {
globals.pausedSince = null;
Navigator.of(context).pushReplacementNamed('/');
} else {
setState(() {
showInactiveOverlay = false;
});
}
break;
case AppLifecycleState.inactive:
debugPrint("didChangeAppLifecycleState: inactive");
setState(() {
showInactiveOverlay = true;
});
break;
case AppLifecycleState.paused:
debugPrint("didChangeAppLifecycleState: paused");
if (widget.pausedTimeAllowed > 0) {
debugPrint("didChangeAppLifecycleState: paused | setting `pausedSince`…");
globals.pausedSince = DateTime.now();
} else {
debugPrint("didChangeAppLifecycleState: paused | navigating to /…");
Navigator.of(context).pushReplacementNamed('/');
}
break;
}
}
When this route is visible on the user’s screen and they put the phone to sleep, I notice that the app's inactive
and paused
states are triggered but on unlocking the device on the app, I briefly (for about 0.5—1 seconds) see a flash of the screen before being navigated to /.
Why is it not already on /?
Additionally, despite the app's inactive
state being triggered, it's noteworthy that I'm not see the inactive overlay (showInactiveOverlay
) that does appear over the content when the app is backgrounded (e.g. when it goes into the switcher).
Am I pulling on the wrong thread by expecting the didChangeAppLifecycleState
callback to handle these?
Upvotes: 3
Views: 1422
Reputation: 7148
TL;DR: I assume that sleep mode triggers inactive -> paused
states, while unlocking triggers the paused
state only.
Based on Flutter's official documentation about lifecycle events, I assume that when the user puts the phone on sleep mode, it first gets to an inactive
state and then to paused
.
On the other hand, when the user locks his screen, which is an unexpected action, it causes the paused
state to be triggered immediately (without the inactive
state).
For that reason, If I understand you correctly, when your user resumes after an unlock, the navigation to the main screen '/' still has to reflect. And that's why they see a flash of the screen before the navigation.
Here is the official description for each lifecycle event:
The application is visible and responding to user input.
The application is in an inactive state and is not receiving user input.
On iOS, this state corresponds to an app or the Flutter host view running in the foreground inactive state. Apps transition to this state when in a phone call, responding to a TouchID request, when entering the app switcher or the control center, or when the UIViewController hosting the Flutter app is transitioning.
On Android, this corresponds to an app or the Flutter host view running in the foreground inactive state. Apps transition to this state when another activity is focused, such as a split-screen app, a phone call, a picture-in-picture app, a system dialog, or another window.
Apps in this state should assume that they may be paused at any time.
The application is not currently visible to the user, not responding to user input, and running in the background.
When the application is in this state, the engine will not call the PlatformDispatcher.onBeginFrame and PlatformDispatcher.onDrawFrame callbacks.
The application is still hosted on a flutter engine but is detached from any host views.
When the application is in this state, the engine is running without a view. It can either be in the progress of attaching a view when engine was first initializes, or after the view being destroyed due to a Navigator pop.
Upvotes: 1