To extend on @CopsOnRoad's answer, you can use a switch statement to make it nice and neat:
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
switch (state) {
case AppLifecycleState.resumed:
print("app in resumed");
break;
case AppLifecycleState.inactive:
print("app in inactive");
break;
case AppLifecycleState.paused:
print("app in paused");
break;
case AppLifecycleState.detached:
print("app in detached");
break;
}
}
Flutter has WidgetsBindingObserver to get notified when app changes
its state from active to inactive states and back. But it actually
includes the state changes of the embedding Activity/ViewController as
well. So if you have a plugin that opens a new activity/view
controller(eg: image picker) or in iOS if you start a FaceID prompt
then WidgetsBindingObserver will report as the app is
inactive/resumed.
This plugin on the other hand reports the events only at app level.
Since most apps need only background/foreground events this plugin is
implemented with just those events. In iOS, plugin reports
didEnterBackgroundNotification and willEnterForegroundNotification
notifications and in Android, plugin reports these using
androidx.lifecycle:lifecycle-process package.
Checkout example/ project to see the differences in action.
People have already posted the answer but this answer is for developers using Getx architecture. You will be able to use the same approach but instead of using it on our stateless widget use it in the controller page. This method helps you to manage foreground and background activities when using Getx state management architecture
class QuotesController extends GetxController with WidgetsBindingObserver{
@override
void onInit() async{
super.onInit();
WidgetsBinding.instance?.addObserver(this);
}
@override
void onClose() {
WidgetsBinding.instance?.removeObserver(this);
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) async{
switch(state){
case AppLifecycleState.resumed:
await player.play();
break;
case AppLifecycleState.inactive:
await player.stop();
break;
case AppLifecycleState.paused:
await player.stop();
break;
case AppLifecycleState.detached:
await player.stop();
// TODO: Handle this case.
break;
}
}
}
I was looking for an easy way to implement that solution and here is the one that works for me:
1. Create a LifecycleEventHandler Class
In this class add two callbacks as attributes, the suspendingCallBack will be invoked when the app goes to the background, and the resumeCallBack will be invoked when the app returns to the foreground.
class LifecycleEventHandler extends WidgetsBindingObserver {
final AsyncCallback resumeCallBack;
final AsyncCallback suspendingCallBack;
LifecycleEventHandler({
required this.resumeCallBack,
required this.suspendingCallBack,
});
@override
Future<void> didChangeAppLifecycleState(AppLifecycleState state) async {
print('state >>>>>>>>>>>>>>>>>>>>>> : ${state}');
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;
}
}
}
2. Listen to the State change.
In the main page of our app we can create a variable to save the lifecycle state, just when the app goes into the background we set the value to true, otherwise the value will be false.
class MainPageState extends State<MainPage> {
bool isAppInactive = false; // if the app is Inactive do some thing
@override
initState(){
super.initState();
WidgetsBinding.instance.addObserver(
LifecycleEventHandler(
resumeCallBack: () async => setState(() {
// The app is now resumed, so let's change the value to false
setState(() {isAppInactive = false; });
}), suspendingCallBack: () async {
// The app is now inactive, so let's change the value to true
setState(() {isAppInactive = true; });
})
);
}
}
And then you can use that variable value to do what you want