flutter
/

GetX App Lifecycle in Flutter: Handle Resume, Pause, Background & Termination

Last Sync: Today

On this page

10
0%
5 min read
Remaining
5 minleft

Click any section to jump — progress syncs automatically

flutter

GetX App Lifecycle in Flutter: Handle Resume, Pause, Background & Termination

Introduction

Flutter apps can be in various states: foreground, background, inactive, or paused. Detecting these state changes is essential for tasks like pausing animations, saving data, or refreshing when the app returns. GetX provides a simple way to listen to app lifecycle events using Get.onAppLifecycleState or by integrating WidgetsBindingObserver with GetX controllers. This guide covers both approaches and best practices.

  1. Using Get.onAppLifecycleState

GetX offers a built‑in method to register a callback that fires whenever the app's lifecycle state changes. You can set it up once in your main() or inside a controller.

DARTRead-only
1
void main() {
  Get.onAppLifecycleState = (state) {
    print('App lifecycle: $state');
    if (state == AppLifecycleState.resumed) {
      // App came to foreground
    } else if (state == AppLifecycleState.paused) {
      // App went to background
    }
  };
  runApp(MyApp());
}

Note: This callback is global. For per‑controller lifecycle handling, consider using WidgetsBindingObserver or a service.

  1. Using WidgetsBindingObserver in a Controller

A more flexible approach is to make a controller implement WidgetsBindingObserver and register it as an observer. This gives you granular control per controller.

DARTRead-only
1
class LifecycleController extends GetxController with WidgetsBindingObserver {
  @override
  void onInit() {
    super.onInit();
    WidgetsBinding.instance.addObserver(this);
  }

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

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    print('Lifecycle state: $state');
    switch (state) {
      case AppLifecycleState.resumed:
        // App is in foreground
        break;
      case AppLifecycleState.inactive:
        // App is transitioning
        break;
      case AppLifecycleState.paused:
        // App is in background
        break;
      case AppLifecycleState.detached:
        // App is about to be destroyed
        break;
    }
  }
}

  1. Creating a Lifecycle Service

For global lifecycle handling that many parts of the app can use, create a service that extends GetxService and implements WidgetsBindingObserver. Other controllers can then listen to its reactive state.

DARTRead-only
1
class AppLifecycleService extends GetxService with WidgetsBindingObserver {
  var appState = AppLifecycleState.resumed.obs;

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

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

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    appState.value = state;
    // Optionally broadcast to other parts
  }

  bool get isInForeground => appState.value == AppLifecycleState.resumed;
}

// Register in initialBinding
Get.put(AppLifecycleService(), permanent: true);

// In another controller
class DataController extends GetxController {
  final AppLifecycleService lifecycle = Get.find();

  @override
  void onInit() {
    super.onInit();
    ever(lifecycle.appState, (state) {
      if (state == AppLifecycleState.resumed) {
        refreshData();
      }
    });
  }

  void refreshData() {
    // fetch fresh data
  }
}

Lifecycle States Reference

StateDescriptionTypical Use
`resumed`App is visible and responding to user inputRefresh data, resume animations, reconnect streams
`inactive`App is visible but not receiving input (e.g., notification shade)Pause interactions, but keep UI visible
`paused`App is in background, not visibleSave user data, pause animations, close connections
`detached`App is about to be terminatedFinal cleanup, but not guaranteed to finish

  1. Common Use Cases

  • Refresh data when app returns to foreground – Use ever on the lifecycle service's state.
  • Pause/Resume animations – Stop heavy animations when app goes to background to save battery.
  • Save user data – Write unsaved changes when the app is paused.
  • Close WebSocket connections – Disconnect when background, reconnect on resume.
  • Analytics tracking – Send session start/end events.

  1. Handling App Termination

The detached state indicates the app is about to be terminated. You can perform final cleanup here, but note that there is no guarantee that the callback will complete. For critical saves, prefer using paused.

DARTRead-only
1
case AppLifecycleState.detached:
  // App is being destroyed
  // Save final state, close connections
  break;

Best Practices

  • Use a single global lifecycle service – Centralise handling and share state.
  • Don't do heavy work in lifecycle callbacks – Avoid blocking the main thread; use asynchronous methods.
  • Dispose resources properly – Remove observers in onClose to prevent memory leaks.
  • Test lifecycle events – Use the Flutter dev tools to simulate background/foreground.
  • Consider platform differences – Lifecycle behavior may differ slightly on iOS vs Android, but the states are consistent.

Common Mistakes

  • ❌ Not removing the observer – Causes memory leaks. ✅ Always call removeObserver in onClose.
  • ❌ Assuming paused means the app is about to be killed – It only means the app is in the background; the user can return. ✅ Use detached for final cleanup.
  • ❌ Performing expensive operations in lifecycle callbacks – May cause jank. ✅ Move heavy work to separate isolates or defer with Future.microtask.
  • ❌ Relying on Get.onAppLifecycleState for per‑controller logic – That callback is global; use a service or controller observer for scoped logic.

Conclusion

Handling app lifecycle events is crucial for building responsive and battery‑efficient Flutter apps. GetX makes this easy with the global Get.onAppLifecycleState callback and the ability to use WidgetsBindingObserver inside controllers and services. By centralising lifecycle logic in a service, you can react to state changes anywhere in your app.

Try it yourself

import 'package:flutter/material.dart';
import 'package:get/get.dart';

void main() {
  // Global lifecycle callback
  Get.onAppLifecycleState = (state) {
    print('Global callback: $state');
  };
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      home: LifecycleDemo(),
      initialBinding: LifecycleBinding(),
    );
  }
}

// Lifecycle service
class LifecycleService extends GetxService with WidgetsBindingObserver {
  var appState = AppLifecycleState.resumed.obs;

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

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

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    appState.value = state;
    print('Service: $state');
  }
}

class LifecycleBinding extends Bindings {
  @override
  void dependencies() {
    Get.put(LifecycleService(), permanent: true);
  }
}

class LifecycleDemo extends StatelessWidget {
  final service = Get.find<LifecycleService>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('App Lifecycle')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Obx(() => Text('Current state: ${service.appState.value}')),
            SizedBox(height: 20),
            Text('Check console for logs'),
          ],
        ),
      ),
    );
  }
}

Test Your Knowledge

Q1
of 3

Which method is used to listen to app lifecycle events globally in GetX?

A
Get.lifecycle
B
Get.onAppLifecycleState
C
Get.observeLifecycle
D
Get.onLifecycleChange
Q2
of 3

What is the correct way to add a lifecycle observer to a GetX controller?

A
Extend GetxController and implement WidgetsBindingObserver, then add and remove observer
B
Use Get.onAppLifecycleState inside the controller
C
Call WidgetsBinding.instance.addObserver automatically
D
It's not possible
Q3
of 3

When should you remove the observer from the controller?

A
onInit
B
onReady
C
onClose
D
didChangeAppLifecycleState

Frequently Asked Questions

What is the difference between `resumed` and `inactive`?

resumed means the app is visible and responding to user input. inactive means it's visible but not receiving user input (e.g., when a notification shade is pulled down).

How do I detect when the app comes back from background?

Listen for AppLifecycleState.resumed. In a service, use ever on the state observable. In a controller, override didChangeAppLifecycleState.

Can I use `GetX` to handle app lifecycle without `WidgetsBindingObserver`?

Yes, Get.onAppLifecycleState provides a simple global callback, but for more control, the observer pattern is recommended.

Does `Get.onAppLifecycleState` work on all platforms?

Yes, it's based on Flutter's native lifecycle and works on Android, iOS, web, and desktop (with some limitations on web).

How to handle Android's 'Don't keep activities'?

When the activity is destroyed, the app will restart with the initial route. You need to rely on persisted state (e.g., GetStorage) to restore session, not on lifecycle callbacks.

Should I use `Get.onAppLifecycleState` or `WidgetsBindingObserver`?

Get.onAppLifecycleState is great for global one-time setup. For per-controller logic or reactive state, use WidgetsBindingObserver inside a service or controller.

Previous

getx session management

Next

getx global error handler

Related Content

Need help?

Explore our comprehensive docs or start a chat with our tech experts.