Pocket Studio Academy
HomePart 22.2

Activities and the lifecycle

Full course11 min read·4 questions

An Activity is one screen and the door Android knocks on. Learn the six moments Android announces, why rotating the phone destroys and rebuilds your screen, and why a counter resets when it does.

The thing that happens when you rotate

Open your app from Part 0. Turn the phone sideways. The screen redraws.

What actually happened is much more violent than it looked. Android destroyed your screen — threw the whole object away — built a brand new one, and drew that instead. Everything the old one was holding in memory went in the bin.

If your app had a score, a half-typed message, or a scroll position, it is gone. Not hidden. Gone.

This is not a bug and it is not going to be fixed. It is the single most important consequence of the , and once you understand why Android does it, an entire category of "why did my app forget things?" questions answers itself.

Think of it like this

Think about a small shop on a high street.

Someone fits it out in the morning: shelves in, stock on them, till plugged in. That is creation. Then the shutters go up and it is visible from the pavement. Then a member of staff stands at the counter and it is genuinely open for business.

Later, someone knocks on the back door and the shopkeeper steps away for a moment — the shop is still lit and visible, but nobody is serving. Then the shutters come down: still fitted out, but you cannot see in. And finally, one day, the whole unit is stripped back to bare walls.

An goes through exactly those stages, and Android calls one of your functions at every single transition. Nothing happens without you being told.

What an Activity actually is

An Activity is two things at once, and beginners usually only hear about the first.

  1. One screen. A thing with a window, that the user sees.
  2. A doorway. The unit Android is able to start from outside — from the , from a notification, from another app's share sheet.

That second job is why an Activity has to be declared in the : Android needs a public list of the doors it is allowed to knock on.

In the old days apps had dozens of Activities — one per screen. Modern apps usually have one. Dice Duel has one. Pocket Notes has one. Focus Flow has one, with several screens inside it, switched by in Part 4. So an Activity is best thought of as "the window your app lives in", not "a page".

The six moments

Android announces every stage of the shop's day by calling a function on your Activity. You override the ones you care about, and ignore the rest.

FunctionAndroid is telling youWhat belongs here
onCreateYou exist. Build yourself.Set up the screen. Called once per instance.
onStartYou are now visible.Start things the user must see updating.
onResumeYou are in front and have focus.Start the camera, resume the game timer.
onPauseSomething is on top of you.Stop the timer. Save anything that must not be lost.
onStopYou are no longer visible.Release heavy things.
onDestroyYou are being thrown away.Last chance to clean up.

Here is an Activity with all six, printing as it goes. Everything is real; you can paste it.

MainActivity.ktkotlin
1class MainActivity : ComponentActivity() {
2
3  override fun onCreate(state: Bundle?) {
4    super.onCreate(state)
5    println("LIFE onCreate")
6    setContent { AppRoot() }
7  }
8
9  override fun onStart() {
10    super.onStart()
11    println("LIFE onStart")
12  }
13
14  override fun onResume() {
15    super.onResume()
16    println("LIFE onResume")
17  }
18
19  override fun onPause() {
20    super.onPause()
21    println("LIFE onPause")
22  }
23
24  override fun onStop() {
25    super.onStop()
26    println("LIFE onStop")
27  }
28
29  override fun onDestroy() {
30    super.onDestroy()
31    println("LIFE onDestroy")
32  }
33}

Two rules apply to every one of these:

  • Always call super. The parent class has real work to do in each of them. Forget it and Android throws SuperNotCalledException and closes your app — see the Error Doctor.
  • Never do anything slow. Every one of these runs on the . A slow onCreate is a slow launch, and a slow onPause is a phone that feels sticky when you press Home.

The paths through the lifecycle

There are only three journeys worth memorising.

Starting up

text
onCreate -> onStart -> onResume

Leaving and coming back

text
onPause -> onStop -> onRestart -> onStart -> onResume

Note what is missing: no onCreate. Pressing Home and returning does not rebuild anything. The Activity was alive the whole time, just hidden.

Rotating

text
1onPause -> onStop -> onDestroy
2onCreate -> onStart -> onResume

Destroyed and rebuilt, in one continuous motion, in under a frame or two.

Why rotation destroys your screen

This looks insane until you know the reason, and then it is obviously right.

Turning the phone is a . So is switching to dark mode, changing the system language, or making the system font bigger. Every one of those may mean different apply. A different layout for landscape. A different theme for night. Different text for French.

Android's answer is brutally simple: rather than trying to patch a live screen, throw it away and build a new one, which will naturally pick up the right resources on its way up. One code path, no special cases, nothing half-updated.

The price is that anything held in your Activity's memory dies with it.

Careful

This is also why you must never test only in portrait. Rotate every screen you build. If your app forgets something on rotation, it will forget the same thing when Android kills it in the background — and that one the user will notice.

Process death — the bigger version of the same problem

Rotation destroys one screen. destroys everything.

When you leave your app and go and use three other apps, Android may need the memory. It quietly kills your entire . Your app is gone. No warning, no callback you can rely on.

Then the user taps your icon expecting to be back where they were, and Android tries to fake it: it starts a fresh process and hands your onCreate a small parcel called — the state: Bundle? parameter you have been passing to super this whole time.

That is why the parameter is nullable. null means "brand new". Not null means "you have been here before, here is what I kept".

The Bundle is for small things only: a scroll position, a selected tab, a few characters of text. Real data belongs in a database or a file. Part 4 builds this properly with and , and Lesson 4.8 comes back to process death specifically.

Where Compose fits

setContent { } installs a Compose screen inside the Activity's window. From that point on, the inside of your app is Compose's business — but the Activity's lifecycle still rules everything.

The practical consequence you will feel first: a value held in a Compose block survives , but not the Activity being destroyed. Rotate, and it resets.

a counter that forgetskotlin
1// Survives recomposition. Does NOT survive rotation.
2var score by remember { mutableStateOf(0) }
3
4// Survives rotation too — Android saves it in the
5// Bundle for you.
6var score by rememberSaveable { mutableStateOf(0) }

One extra word, rememberSaveable, and the counter survives. Lesson 3.5 explains both properly. For now the important thing is knowing why the first one forgets: the Activity died.

Try it in Pocket Studio

You are going to watch the whole lifecycle happen, live.

  1. Open Pocket Studio, tap Projects, open your Part 0 app.
  2. Tap Editor and open MainActivity.kt.
  3. Add the six overrides from the code block above. Keep every super call.
  4. Tap Build and press Run.
  5. Open Logcat in the Build tab and type LIFE into its filter box. You should see onCreate, onStart, onResume.
  6. Press Home. Watch onPause then onStop appear.
  7. Tap the app icon again. Watch onRestart, onStart, onResume — with no onCreate.
  8. Make sure auto-rotate is on in your phone's quick settings, then turn the phone sideways. Watch all six fire: destroy, then create again.
  9. Swipe the app away in the recents view. Watch onDestroy.
Error Doctor5 common errors
android.util.SuperNotCalledException: Activity {com.nativeworks.diceduel/.MainActivity} did not call through to super.onCreate()
MeansYou overrode a lifecycle function and forgot to call the parent version. The parent does essential setup, so Android refuses to continue with a half-built Activity.
FixAdd super.onCreate(state) as the first line of your override. The same applies to every one of the six — super.onStart(), super.onPause() and so on.
e: file:///…/MainActivity.kt:22:3 'onStart' overrides nothing
MeansKotlin cannot find a function with that exact name and signature in the parent class, so there is nothing to override. Nearly always a spelling or capital-letter slip.
FixCheck the capitals: it is onStart, not OnStart or onstart. Also check the parameters — onCreate takes one Bundle?, the others take none.
java.lang.RuntimeException: Unable to start activity ComponentInfo{…}: java.lang.NullPointerException: Attempt to invoke virtual method … on a null object reference
MeansYour onCreate used something that has not been set up yet. Order matters inside onCreate — a value declared further down the file is not ready at the top of it.
FixRead down the to the first line naming your own file, and check what that line uses. Move the setup above the use, or make the value lazy.
android.view.WindowLeaked: Activity com.nativeworks.diceduel.MainActivity has leaked window DecorView@1f3a2b1[] that was originally added here
MeansA dialog was still on screen when the Activity was destroyed — very often because the phone was rotated while it was showing. The dialog outlived the screen it belonged to.
FixIn Compose, show dialogs from Compose (if (showDialog) { AlertDialog(...) }) rather than creating an Android dialog by hand. Then the dialog dies with the screen automatically.
java.lang.IllegalStateException: Method addObserver must be called on the main thread
MeansLifecycle bookkeeping is only allowed on the . Something touched it from a background instead.
FixMove the call back onto the main thread. In Compose that usually means doing the work inside a LaunchedEffect rather than in a raw background thread.
Recap
  • An is one window and the doorway Android can start your app through. Modern apps normally have exactly one.
  • Six callbacks announce every stage: onCreate, onStart, onResume, onPause, onStop, onDestroy. Always call super; never be slow.
  • A — rotation, dark mode, language — destroys and rebuilds the Activity so the right get chosen.
  • does the same thing to your whole app, without warning. The Bundle? in onCreate is Android's small consolation prize.
  • Anything in remember dies on rotation; rememberSaveable does not.
  • Next: the file Android reads before any of this — the AndroidManifest, line by line.