Skip to content
1 of 3 project slots open
Writing
Fundamentals · part 2 of 55 min read

The Android lifecycle, drawn

Six callbacks, configuration changes, and process death: why screens forget things and how to stop it.

Meer Habib

Senior Mobile Engineer · Chittagong

Android's lifecycle has more callbacks than iOS, but the hard part isn't memorising them. It's the two ways your screen gets destroyed while the user thinks nothing happened: configuration changes and process death.

The activity loop

CreatedonCreateStartedvisibleResumedinteractivePausedpartly hiddenStoppednot visibleDestroyedfinished or config changeProcess killedonStartonResumeonPauseonResumeonStoponDestroyonRestart → onStartuser returns: onCreate(savedState)memory pressure
Fig. 1Activity callbacks. The dashed path is process death: the part most apps get wrong.

An Activity moves through six states, and each move has a callback:

  • onCreate: set up the screen once. Inflate the UI, restore saved state.
  • onStart: you're visible.
  • onResume: you're in front and taking input.
  • onPause: something came in front but you may still be partly visible, like the system permission dialog.
  • onStop: you're no longer visible.
  • onDestroy: you're finished, or you're about to be rebuilt.

Visible lives between onStart and onStop. Interactive lives between onResume and onPause. Put work on the matching pair: start a camera preview in onResume, release it in onPause.

Destroyed on purpose: configuration changes

Rotate the phone, switch to dark mode, change the language or the font size, resize a window. By default Android destroys the activity and creates it again with the new configuration.

That's why state that lives only in a view or a field disappears on rotation. Two tools fix it:

  • ViewModel survives configuration changes. Keep screen state and in-flight work there.
  • Saved state (SavedStateHandle or onSaveInstanceState) is a small bundle the system keeps for you. It survives something the ViewModel doesn't.

Destroyed without asking: process death

When your app is in the background and the system needs memory, it can kill the whole process. No onDestroy. Your singletons, your in-memory cache, your ViewModels: gone.

Then the user comes back from the recents screen. Android recreates the activity they were on and hands it the saved bundle, so the screen looks like it continued. It didn't. Anything you didn't save is missing, and code that assumes "the list was loaded on the previous screen" crashes.

If a screen can't rebuild itself from its saved state and your storage, it has a process-death bug.

You can reproduce it on purpose. Put the app in the background, then:

adb shell am kill com.example.app

Or turn on Don't keep activities in developer options, and walk through your app.

How the system decides who to kill

Processes are ranked by what the user can see:

  1. Foreground: the activity in front, or a foreground service.
  2. Visible: on screen but not in front.
  3. Service: running a started service.
  4. Cached: in the background, kept around to be fast. First to go.

Most apps spend most of their life in the last group.

Doing work in the background

Android is strict about background work, and has become stricter with every release:

  • WorkManager for work that must happen eventually: uploads, syncs, cleanup. It survives restarts and respects battery.
  • Foreground services for work the user is actively aware of, like a call or navigation. They need a visible notification, and on recent versions a declared service type.
  • Doze and App Standby defer jobs, alarms and network access when the phone is idle. Exact alarms need a special permission.

If you're tempted to keep a service alive "just in case", that's the job WorkManager was built for.

In Compose

Collect flows in a way that stops when the screen isn't visible:

val state by viewModel.state.collectAsStateWithLifecycle()

It pauses collection when the lifecycle drops below STARTED and resumes when it comes back, which saves battery and avoids updating UI no one can see.

In React Native

AppState reports "active" and "background" on Android. There's no "inactive", but Android has two extra events, focus and blur, for moments like pulling down the notification shade.

AppState.addEventListener("change", (s) => s === "background" && persistDraft());
AppState.addEventListener("blur", () => pauseVideo());

Process death applies to React Native too. When Android restores your activity, the JavaScript runtime starts fresh. Persist navigation state and drafts if the app should come back to where the user left it.

A checklist

  • State the user would miss goes in a ViewModel and saved state or storage.
  • Every screen can rebuild from its arguments plus storage. Test it with am kill.
  • Pair your work: onStart/onStop for visible things, onResume/onPause for input and camera.
  • Long work goes to WorkManager, not a service you hope stays alive.

Before this, the iOS side. After it, what happens between the tap and the database.

Building something like this?

Booking new projects for Q4. Replies within 24h.