Flutter - Detect Application In Foreground/Background State

This tutorial is about how to detect when a Flutter application comes to the foreground or goes to the background. This includes the list of possible application lifecycle states with the explanation.

A running Flutter application has a lifecycle state. Detecting state changes is necessary for some applications. For example, it can be necessary to fetch the latest data when the application goes back to the foreground or pause a running task when it goes to the background. This tutorial explains the possible states and how to detect when the state changes.

Application Lifecycle States

First, you need to understand the possible states of an application. Flutter has four application states. Below is the list of states along with the explanation.

Resumed state

In this state, the application is visible to the user (in the foreground) and it can receive user input.

Inactive state

In this state, the application may still be visible to the user (in the foreground) but it doesn't receive user input and it may go to the paused state at any time.

On Android, it can happen when the focus changes to another activity, such as a phone call, a system dialog, a split-screen application, or a pop-up window. On iOS, it can happen when there is a phone call, entering the app switcher, responding to a TouchID request, or when the UIViewController is transitioning.

Paused state

In this state, the application is not visible to the user and not responding to user input. It runs in the background.

Detached state

In this state, the application is detached from any host views. The possible conditions are when the engine first initializes (in the process of attaching a view) or being destroyed from a Navigator pop (such as pressing the back button on the application's home page).

Detect Lifecycle State Change

Detecting lifecycle changes in Flutter is quite simple. You need to create a State class that uses the WidgetsBindingObserver interface. If you look at the interface, there is a method named didChangeAppLifecycleState. It's called when the application state changes, such as when it goes to the background or returns to the foreground. The method will be invoked with an argument whose value is the current state. Therefore, you can override the method to listen to the events when the lifecycle state changes.

To make it works, the State class has to be registered as a binding observer by calling WidgetsBinding's addObserver method inside the initState method. You also need to call WidgetsBinding's removeObserver to unregister the class as an observer when it's removed from the tree.

class _GetDeviceLocale extends State<DetectLifecycleState>
    with WidgetsBindingObserver {

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

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

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    switch (state) {
      // Write your code
    }
  }
}

Full Code

  import 'package:flutter/material.dart';
  
  void main() => runApp(const MyApp());
  
  class MyApp extends StatelessWidget {
  
    const MyApp({Key? key}) : super(key: key);
  
    @override
    Widget build(BuildContext context) {
      return const MaterialApp(
        title: 'Woolha.com Flutter Tutorial',
        home: DetectLifecycle(),
      );
    }
  }
  
  class DetectLifecycle extends StatefulWidget {
  
    const DetectLifecycle({Key? key}) : super(key: key);
  
    @override
    State<StatefulWidget> createState() {
      return _DetectLifecycleState();
    }
  }
  
  class _DetectLifecycleState extends State<DetectLifecycle>
      with WidgetsBindingObserver {
  
    @override
    void initState() {
      WidgetsBinding.instance.addObserver(this);
      super.initState();
    }
  
    @override
    void dispose() {
      WidgetsBinding.instance.removeObserver(this);
      super.dispose();
    }
  
    @override
    void didChangeAppLifecycleState(AppLifecycleState state) {
      switch (state) {
        case AppLifecycleState.resumed:
          print("RESUMED");
          break;
        case AppLifecycleState.inactive:
          print("INACTIVE");
          break;
        case AppLifecycleState.paused:
          print("PAUSED");
          break;
        case AppLifecycleState.detached:
          print("DETACHED");
          break;
      }
    }
  
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: const Text('Woolha.com Flutter Tutorial'),
          backgroundColor: Colors.teal,
        ),
        body: const SizedBox(
          width: double.infinity,
          child: Center(
            child: Text('Woolha.com'),
          ),
        ),
      );
    }
  }

Summary

There are four application lifecycle states: resumed, inactive, paused, and detached. To detect when the state changes, just implement WidgetsBindingObserver and override the didChangeAppLifecycleState method.