Skip to main content

Configuration changes and state reconstruction

Configuration can change while the process lives​

Examples include:

  • window/display size and orientation;
  • fold/unfold and multi-window resize;
  • font size/weight;
  • locale and layout direction;
  • light/dark mode;
  • keyboard/peripheral availability;
  • density/display changes.

Android commonly recreates an Activity so the new instance re-resolves appropriate resources.

Old Activity/View tree destroyed
↓
New configuration becomes active
↓
New Activity/View tree created
↓
Resources selected again
↓
State reconstructed

Recreation is a feature​

It allows values-night, localized strings, dimensions, layout direction, and other configuration-specific resources to apply consistently. Preventing recreation transfers responsibility for updating every affected resource and subsystem to your code.

State categories during recreation​

StateExampleOwner
UI element stateText cursor, scrollView/Compose saveable state when appropriate
Screen stateLoaded order, errorsViewModel derived from repository
Restoration inputorderId, selected tabSavedStateHandle/arguments
Durable business stateDraft checkoutDatabase/server
Configuration representationTranslated string, dimensionsRe-resolve from new Context/resources

Practical ViewModel​

class OrderViewModel(
savedState: SavedStateHandle,
repository: OrderRepository
) : ViewModel() {
private val orderId = requireNotNull(savedState.get<String>("orderId"))

val state = repository.observe(orderId)
.map(::toUiState)
.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5_000),
OrderUiState.Loading
)
}

The ViewModel can survive eligible configuration recreation. Its UI state should not store Activity, View, or old configuration Context.

Stale resource trap​

❌ Store translated text in ViewModel​

data class UiState(val errorMessage: String)

If the locale changes while ViewModel survives, the string can remain in the old language.

✅ Store semantic error and resolve in UI​

sealed interface CheckoutError {
data object NetworkUnavailable : CheckoutError
data object PaymentDeclined : CheckoutError
}

UI maps the semantic value to current stringResource(...). For server-provided messages, define localization/formatting strategy separately.

android:configChanges​

<activity
android:name=".PlayerActivity"
android:configChanges="orientation|screenSize" />

This tells Android that your Activity handles specified changes and receives onConfigurationChanged() rather than normal recreation for them.

❌ Avoid as a lifecycle bug patch​

Declaring every flag does not preserve process state and requires manually updating affected UI/resources. New platform/configuration categories and multi-window behavior make blanket handling fragile.

✅ Use only for a justified specialized need​

Examples may include an expensive realtime surface where a controlled subset can be safely reconfigured. Document every handled change and test resource/theme/window updates.

Orientation locking is not state architecture​

Locking portrait may be a product requirement for a specialized experience. It should not be used solely to hide recreation crashes; foldables, resizing, locale, dark mode, and process death still exist.

Compose configuration​

Reading configuration/resources inside composition creates state-dependent UI that recomposes when the relevant value changes. Do not copy LocalConfiguration.current into a process singleton and expect it to remain current.

Prefer adaptive APIs such as window size classes/current constraints over orientation labels. Two landscape windows can have very different usable widths.

Testing matrix​

  • rotate while loading and after content;
  • resize in multi-window;
  • fold/unfold on representative emulator/device;
  • switch light/dark;
  • change locale/layout direction;
  • increase font/display size;
  • connect hardware keyboard;
  • recreate Activity and separately kill process.

The last two are different tests.

Interview-ready answer

Configuration changes commonly recreate Activities so Android can re-resolve resources. I keep durable data in repositories, screen state in ViewModel, small restoration keys in saved state, and resolve strings/themes from the current UI Context. I do not use configChanges or orientation locking to hide lifecycle bugs; manual handling is reserved for measured specialized cases and must update every affected resource/system.

Exercises​

  1. Explain why ViewModel can display an old-language error after locale change.
  2. Design state restoration while rotating during payment submission.
  3. List what a video player must update if it handles screen-size changes manually.