Android Fundamentals: Activities & Lifecycle

Reviewed & published by Brayan K

Behind every Compose screen sits an Activity with a well-defined lifecycle. Understanding when the system creates, pauses, and destroys your screen is essential to avoid bugs and leaks.

Part of the free Kotlin course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

By the end you'll trace the lifecycle callbacks, see why a ViewModel survives rotation, and launch coroutines safely with viewModelScope.

What You'll Learn in This Lesson

1️⃣ The Activity Lifecycle

An Activity is a single screen. The OS calls lifecycle methods in a predictable order: onCreate then onStart then onResume on the way up, and onPause then onStop then onDestroy on the way down.

import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity

class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d("LC", "onCreate")   // one-time setup goes here
    }

    override fun onStart() {
        super.onStart()
        Log.d("LC", "onStart")    // becoming visible
    }

    override fun onResume() {
        super.onResume()
        Log.d("LC", "onResume")   // foreground & interactive
    }

    override fun onPause() {
        super.onPause()
        Log.d("LC", "onPause")    // losing focus
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d("LC", "onDestroy")  // final cleanup
    }
}

Use each callback for the right job: one-time setup in onCreate, acquiring resources in onStart/onResume, releasing them in onPause/onStop.

2️⃣ ViewModel and viewModelScope

A ViewModel holds UI state that survives configuration changes like rotation. Launch asynchronous work in viewModelScope so it's cancelled automatically when the ViewModel is cleared.

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch

class CounterViewModel : ViewModel() {
    // UI state that survives configuration changes (rotation).
    private val _count = MutableStateFlow(0)
    val count = _count.asStateFlow()

    fun increment() {
        _count.value += 1
    }

    fun loadAfterDelay() {
        // viewModelScope cancels this coroutine when the ViewModel is cleared.
        viewModelScope.launch {
            delay(1000)
            _count.value = 100
        }
    }
}

Your turn. Replace the TODO, then run and read Logcat.

// 🎯 YOUR TURN — replace the TODO then reason about the logs.

import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity

class ProfileActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 1) Log the FIRST lifecycle stage.
        //    👉 replace TODO with: Log.d("LC", "onCreate")
        TODO
    }

    override fun onResume() {
        super.onResume()
        Log.d("LC", "onResume")
    }
}

Mini-Challenge: A Name ViewModel

Build a ViewModel that holds a name in state and explain why it survives rotation.

// 🎯 MINI-CHALLENGE: a name ViewModel.
//
// 1. Create class NameViewModel : ViewModel().
// 2. Hold a MutableStateFlow<String> starting at "" exposed as a StateFlow.
// 3. Add fun setName(value: String) that updates the state.
// 4. Explain (in a comment) why the name survives screen rotation.
//
// ✅ setName("Ada") -> the exposed state emits "Ada",
//    and it is retained across configuration changes.

class NameViewModel /* : ViewModel() */ {
    // your code here
}

Common Errors (and the fix)

Pro Tips

📋 Quick Reference — Lifecycle

CallbackWhen / Use
onCreate()One-time setup (setContent)
onStart()Becoming visible
onResume()Foreground & interactive
onPause()Losing focus
onDestroy()Final cleanup
viewModelScopeLifecycle-aware coroutines

🎉 Lesson Complete!

Practice quiz

What is an Activity in Android?

  • A background service
  • A single, focused screen the user interacts with
  • A database table
  • A build configuration

Answer: A single, focused screen the user interacts with. An Activity represents one screen and is an entry point for user interaction.

Which lifecycle callback runs first when an Activity is created?

  • onResume()
  • onStart()
  • onCreate()
  • onPause()

Answer: onCreate(). onCreate() is the first callback, where you do one-time setup like setContent.

Which callback runs when the Activity is about to become visible but not yet interactive?

  • onStart()
  • onDestroy()
  • onPause()
  • onStop()

Answer: onStart(). onStart() runs as the Activity becomes visible, before onResume() makes it interactive.

Which callback signals the Activity is in the foreground and interactive?

  • onCreate()
  • onResume()
  • onStop()
  • onRestart()

Answer: onResume(). onResume() is called when the Activity reaches the foreground and can take input.

When another activity comes to the foreground, which is called first on the current one?

  • onDestroy()
  • onCreate()
  • onPause()
  • onStart()

Answer: onPause(). onPause() runs first as the Activity loses focus, before onStop().

Which callback is the last one before an Activity is destroyed?

  • onPause()
  • onStop()
  • onFinish()
  • onDestroy()

Answer: onDestroy(). onDestroy() is the final callback before the Activity is torn down.

What is the main purpose of a ViewModel?

  • To draw UI directly
  • To hold and manage UI-related state across configuration changes
  • To replace the manifest
  • To store passwords

Answer: To hold and manage UI-related state across configuration changes. A ViewModel holds UI state and survives configuration changes like rotation.

Why does a ViewModel survive screen rotation when an Activity does not?

  • It is stored on disk
  • It is a singleton
  • It is scoped to the lifecycle owner and retained across configuration changes
  • Rotation never destroys anything

Answer: It is scoped to the lifecycle owner and retained across configuration changes. The ViewModel is retained by the framework across configuration changes, unlike the Activity instance.

What is viewModelScope used for?

  • Defining XML layouts
  • A CoroutineScope tied to the ViewModel's lifecycle for launching coroutines
  • Storing the back stack
  • Inflating menus

Answer: A CoroutineScope tied to the ViewModel's lifecycle for launching coroutines. viewModelScope launches coroutines that are automatically cancelled when the ViewModel is cleared.

What happens to coroutines in viewModelScope when the ViewModel is cleared?

  • They are paused forever
  • They keep running in the background
  • They are automatically cancelled
  • They restart

Answer: They are automatically cancelled. When the ViewModel is cleared (in onCleared), viewModelScope cancels its coroutines to avoid leaks.

Continue this course

Frequently asked questions

What is an Activity and how does it relate to Compose?

An Activity is a single screen and an entry point into your app — the OS launches it and delivers lifecycle callbacks. With Compose, you typically have one (or few) Activity that calls setContent { } in onCreate to host your composables, and you navigate between screens using Navigation-Compose rather than launching a new Activity per screen.

What's the order of the main lifecycle callbacks?

Starting up: onCreate (one-time setup) then onStart (becoming visible) then onResume (foreground and interactive). Going away: onPause (losing focus) then onStop (no longer visible) then onDestroy (final cleanup). Returning from stopped uses onRestart then onStart then onResume. Knowing this order tells you where to acquire and release resources.

Why use a ViewModel instead of keeping state in the Activity?

An Activity instance is destroyed and recreated on configuration changes such as rotation, so state stored in it is lost. A ViewModel is retained across those changes, so UI state survives. It also separates UI logic from the screen, making code testable. The Activity (or composable) observes the ViewModel's state and just renders it.

What is viewModelScope and why does it matter?

viewModelScope is a CoroutineScope tied to the ViewModel's lifecycle. Coroutines you launch in it — for network calls, database reads, timers — are automatically cancelled when the ViewModel is cleared (onCleared). That prevents leaks and 'zombie' work after the screen is gone. It's the idiomatic place to start asynchronous work that backs the UI.