How does flutter handle mobile screen being turned off? - flutter

Only some Dart code runs when the screen is off. What does Flutter do when the mobile phone screen is turned off? Does it stop rendering but still runs specific Dart code?
In my case, Dart callback functions (passed to Flutter plugins) are called even when the screen is off. I want to customise/ control this behaviour, as I am running computational costly code that shouldn't run when the user can't see the output. I can already run code when the screen is turned off (such as by using screen_state flutter plugin or using ScreenStateObserver as provided by Miguel Ruivo, but it has limitations. I am not able to pop the route using Navigator.pop(). I also want to generally understand how Flutter is affected when the screen is off.

You want to take a look at WidgetsBindingObserver mixin as it will provide you with the different application lifecycle to your widget's state.
You'll then want to subscribe on initState()
#override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
and remove the listener on dispose()
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
and access the different states on didChangeAppLifecycleState()
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
switch (state) {
case AppLifecycleState.resumed:
print('app resumed');
break;
case AppLifecycleState.inactive:
print('app inactive');
break;
case AppLifecycleState.paused:
print('app paused');
break;
case AppLifecycleState.detached:
print('app deatched');
break;
}
}

Related

Flutter Make api call when home button(middle android button) is pressed and user comes back on app

In my app i have screens that fetched data from the Api, and sometimes the backend can update or change something on the api, so if the user is using the app, and the user presses the home button (middle android button. the circle) and comes back to the app later, i dont see the data being updated so no api call is being made, but when i press the back button and come back to the app the api call is being made same as when i close the app and remove it from the opened app history and open it again, the api call is being made, so i need that to happened the same when the home button is pressed, the user gets out the app by pressing the home button, comes back and the api call will be made. I looked in to it and i was told i need to use WidgetsBindingObserver class. Any help would be appreciated, let me know if you need any code to post.
i tried this but it wont work
class _StopWorkingScreenState extends State<StopWorkingScreen>
with WidgetsBindingObserver {
late Future<Response> futureDataForStatus;
#override
void initState() {
super.initState();
futureDataForStatus = getLocationStatus();
WidgetsBinding.instance!.addObserver(this);
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
switch (state) {
case AppLifecycleState.inactive:
print("Inactive");
break;
case AppLifecycleState.paused:
print("Paused");
break;
case AppLifecycleState.resumed:
futureDataForStatus;
break;
}
}
You need to call the function in your switch operator, not just pass a variable.
You could do something like:
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
switch (state) {
...
case AppLifecycleState.resumed:
setState(() {
futureDataForStatus = getLocationStatus();
});
break;
}
}
This will update the state on opening of the app and reload the view with new data (assuming you are using futureDataForStatus as future of a FutureBuilder somewhere on the page.

flutter didChangeAppLifecycleState never runs

I implemented the WidgetsBindingObserver, but the app is NEVER sent to the background so it doesn't recognize the AppLifecycleState.resumed
this is the current implementation
#override
void didChangeAppLifecycleState(AppLifecycleState state) async {
print('\n\ndidChangeAppLifecycleState');
switch (state) {
case AppLifecycleState.resumed:
print('\n\nresumed');
_mymethod();
break;
case AppLifecycleState.inactive:
print('\n\ninactive');
break;
case AppLifecycleState.paused:
print('\n\npaused');
break;
case AppLifecycleState.detached:
print('\n\ndetached');
break;
}
}
to simulate the process i do the next in android
run the project as --release
open the widget with the WidgetsBindingObserver
open another app (like chrome or phone settings)
return to the app
when returning to the app i can see my widget on screen, the app doesn't restart, but NONE of the prints appears on the console not event the print('\n\ndidChangeAppLifecycleState'); and _mymethod(); is never executed
The WidgetsBindingObserver mixin requires a bit more work than merely implementing the interface. You also need to add the following to your widget state class:
#override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}

How to show an alert when user is trying to go in background mode?

I want to show a simple alert dialog box when user push an app to background and ask something like Are you sure? before losing all the important information on that page. I am using multi-screen form to get user data and don't want to break the flow so a simple message would help.
I am trying to achieve this with WidgetsBindingObserver and AppLifecycleState but it doesn't seem to work.
#override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
#override
void dispose() {
super.dispose();
WidgetsBinding.instance.removeObserver(this);
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
switch (state) {
case AppLifecycleState.paused:
print('paused');
AlertDialog(
title: Text('Are you sure?'),
);
break;
default:
break;
}
}
Paused is getting print so the functionality is working fine, now I need some way to restrict this with Alert Dialog box or any other way.

didChangeAppLifecycleState doesn't work as expected

I hope I understand how didChangeAppLifecycleState worked correctly.
I have page A and page B . When I click the back device button from page B ( Navigator.of(context).pop(); ), I expect didChangeAppLifecycleState in pageA will get called, but it doesn't.
PageA
class _ABCState extends State<ABCrList> 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) {
setState(() {
print(...);
});
}else{
print(state.toString());
}
}
....
This is the initState in pageA. The function used to call backend service.
#override
void initState() {
super.initState();
_bloc.getList(context); // return list and populate to ListView
});
}
The way you're thinking it is Android's way where onResume works, but in Flutter, things don't happen this way.
Generally, this gets called when the system puts the app in the background or returns the app to the foreground.
There are mainly 4 states for it:
resumed: The application is visible and responding to user input.
inactive: The application is in an inactive state and is not receiving user input.
paused: The application is not currently visible to the user, not responding user input, and running in the background.
detached: The application is still hosted on a flutter engine but is detached from any host views.
Edit:
When you're navigating to PageB from PageA, use something like:
Navigator.pushNamed(context, "/pageB").then((flag) {
if (flag) {
// you're back from PageB, perform your function here
setState(() {}); // you may need to call this if you want to update UI
}
});
And from PageB, you'll can use
Navigator.pop(context, true);

Flutter Capture event when app comes to Foreground from triggered Intent

I am trying to pull off some basic stuff here. Scenario: I am checking for GPS status on init() using isLocationServiceEnabled. If the GPS is off, I'm showing a popup that redirects to Location settings using AndroidIntent. If hit back without turning on the GPS, I want to capture the event when my app comes to foreground. I guessed it has to do with the lifecycle and tried like below, nothing gets print on the console
AppLifecycleState _notification;
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
setState(() {
_notification = state;
print('onResumed called 1');
print(_notification);
});
if( state == AppLifecycleState.resumed){
print('onResumed called 2');
}
}
Am I missing something here?
Did you extend class with WidgetsBindingObserver like so:
class _WhateverWidget extends State<WhateverWidget> with WidgetsBindingObserver
and then initialize an instance like so:
#override void initState() {
WidgetsBinding.instance.addObserver(this);
super.initState();
}
#override void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}