How do I check if the Flutter application is in the foreground or not?

I don't want to show notification when the app is in foreground. How can I check live state of my app?


Solution 1:

In your State<...> class you need to implement WidgetsBindingObserver interface and listen for widget state changes. Something like this:

class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {
  AppLifecycleState _notification; 
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    setState(() {
      _notification = state;
    });
  }

  @override
  initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    ...
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }
}

Then when you want to know what is the state, check

 _notification.index property. _notification == null => no state changes happened, 
0 - resumed, 
1 - inactive, 
2 - paused.

Solution 2:

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;
    }
}

Solution 3:

Simply create a bool variable which will keep track of all your background/foreground stuff.

Full code:

class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
  // This variable will tell you whether the application is in foreground or not. 
  bool _isInForeground = true;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance!.addObserver(this);
  }
  
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    _isInForeground = state == AppLifecycleState.resumed;
  }

  @override
  void dispose() {
    WidgetsBinding.instance!.removeObserver(this);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) => Scaffold();
}

Solution 4:

Also there is a package named flutter_fgbg for this.

Example:

FGBGNotifier(
    onEvent: (event) {
        print(event); // FGBGType.foreground or FGBGType.background
    },
    child: ...,
)

Or:

subscription = FGBGEvents.stream.listen((event) {
    print(event); // FGBGType.foreground or FGBGType.background
});

// in dispose
subscription.cancel();

Why:

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.

Example link.

Solution 5:

You can use a global variable to save the state for easy to use.

For example:

AppLifecycleState appLifecycleState = AppLifecycleState.detached;

Save the state in your AppState:

@override
void didChangeAppLifecycleState(AppLifecycleState state) {
  appLifecycleState = state;
}

Now you can use it easily when you need:

if (appLifecycleState == AppLifecycleState.paused) {
  // in background
}