Phase 3 · Navigation & ArchitectureModule 22~35 min read

Lifecycle & State Restoration

Distinguish recomposition, rotation, system process death and persistent storage; verify small-input restoration with a hands-on lab.

Lifecycle & State Restoration: learning goals

Distinguish a recomposition from activity recreation, system process death and a fresh launch. Store each piece of state according to how long it must remain meaningful, then verify those choices with separate experiments.

Project setup and scope

Use lifecycle-viewmodel-compose, lifecycle-runtime-compose and the saved-state support supplied by the project's Activity/Navigation setup. Acquire the ViewModel through viewModel() or the configured factory so a SavedStateHandle is provided; do not manually construct a new screen ViewModel in a composable.

Build the mental model

Composition lifetime, Activity lifetime and process lifetime are separate. A recomposition can rerun a function while retaining remembered values. Rotation commonly recreates an Activity, while a ViewModel owned by the retained store remains available. A killed process loses ordinary memory, including that ViewModel.

rememberSaveable and SavedStateHandle store small reconstruction inputs through Android's saved-state mechanism. They help when the system recreates an existing task; they do not guarantee recovery after every task dismissal, force-stop, or user-cleared app data event. A durable session record belongs in Room or another persistent store.

The useful question is not 'How do I keep every object alive?' but 'What minimum input lets me reconstruct the screen?' Save a search query and selected ID, then reload records and recompute filtered results. Large lists and bitmaps can exceed saved-state limits and become stale copies.

collectAsStateWithLifecycle makes a lifecycle-aware subscription for UI collection. It does not necessarily stop all upstream work: sharing policy and other collectors determine what the producer continues doing. Choose both observation and production lifetimes deliberately.

Choose the right approach

NeedApproach
Temporary expansion while displayedremember when losing it on leaving composition is acceptable.
Short editable UI inputrememberSaveable for local UI state, or SavedStateHandle when used by screen logic.
Screen business state during rotationViewModel; reconstruct needed state after process recreation.
User-created records across launchesRoom/files; persist at a defined transaction boundary.
Continuous UI observationcollectAsStateWithLifecycle plus a deliberate upstream sharing policy.

Predict and trace the behavior

Android concept labInteractive walkthrough

Lifecycle & State Restoration

Predict what happens next. Follow the diagram, then explain the change in your own words.

Representative concept map

State down · events up

state
State ownerThe only place that updates the valuecurrent state
↓ valueevent ↑
Compose UIReads state · reports user actions
Render current valueUser action ↑

One owner updates the value. The UI receives a value and sends actions back through callbacks.

Explore this general model independently. The lesson sequence below follows its own example.

Read: The UI receives a value from its state owner.

Lesson sequence1 / 4
Step 1 of 4

Type query

The user types 'Compose'. The screen sends the input to its ViewModel.

Up nextSave input
A teaching simulation; diagrams illustrate the concept. Run the Kotlin examples in Android Studio.

Worked Kotlin example

SearchViewModel.kt
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.StateFlow

class SearchViewModel(private val savedState: SavedStateHandle) : ViewModel() {
    val query: StateFlow<String> = savedState.getStateFlow("query", "")

    fun onQueryChanged(value: String) {
        savedState["query"] = value
    }
}

// In a composable, with lifecycle-runtime-compose and runtime getValue imports:
// val query by viewModel.query.collectAsStateWithLifecycle()
// SearchField(query = query, onQueryChanged = viewModel::onQueryChanged)
// Reload/derive actual search results from the repository, not a saved large list.
Focused teaching example. Keep your generated package/theme and complete the explicitly labeled integration points.
  1. getStateFlow supplies an initial empty value and emits saved changes through a read-only StateFlow. Updating SavedStateHandle updates the exposed query.
  2. The input callback is an event boundary. A stateless field needs only a String and a callback, making previews and UI tests independent of the ViewModel.
  3. Use the query to derive results from current data. If a selected ID no longer exists after reconstruction, show a not-found or cleared-selection state instead of crashing.

Student practice and expected behavior

Add a searchable fake directory. Log a nonpersonal ViewModel creation marker, save only its query, and compare recomposition, rotation and system process recreation on a test emulator.

  • A normal input update changes the text without creating a new Activity or ViewModel.
  • Rotation restores the UI and keeps the destination's ViewModel while its owner remains retained.
  • For system process recreation: type a query, press Home, run adb shell am kill YOUR_TEST_PACKAGE, then return through Recents. Verify a new owner reconstructs the query when saved state is restored.
  • Force-stop, clearing app data and dismissing a task are separate experiments; do not claim they are equivalent to system process recreation.

Write down the input, expected outcome and observed outcome for each check. Include a screenshot, a short recording or a nonpersonal diagnostic trace appropriate to the behavior you are proving.

Debugging clinic

  • Developer option 'Don't keep activities' exercises Activity destruction, not the same failure as killing the process.
  • A manually instantiated ViewModel can bypass its proper store/factory and saved-state setup.
  • A saveable query does not make a session database durable. Keep persistent records and reconstruction inputs separate.
  • A lifecycle-aware collector does not cancel every producer or background job automatically.

Instructor prompts

  1. Draw four nested lifetimes and ask students to place a query, a ViewModel, a coroutine and a saved session.
  2. Have learners predict which object is recreated before each emulator experiment; compare with creation markers.
  3. Ask what the app should show when a restored selected ID points to a deleted record.

Teach-back checkpoint

Ask a student to describe one incorrect approach, reproduce the resulting behavior, and explain the repair using ownership, lifetime, constraints or trust boundaries from this lesson.

Quick check and references

Quick check

1. Which object automatically survives arbitrary system process death in memory?

2. What is a sensible SavedStateHandle value?

Continue with the phase capstone after demonstrating the practice checks. Use the official documentation to verify APIs against your project's selected dependency versions.