Skip to main content

Android modeling, corner cases, and interviews

Practical Android state​

sealed interface ProfileUiState {
data object Loading : ProfileUiState
data class Content(val user: UserUi) : ProfileUiState
data class Error(val message: String, val retryable: Boolean) : ProfileUiState
}

Android/Compose-only use: a composable can use an exhaustive when and access branch-specific data through smart casts.

Corner cases​

  • Base constructor calls to open members can execute before subclass initialization; avoid calling overridable members during construction.
  • A data class compares only primary-constructor properties automatically.
  • copy() does not deeply copy mutable lists or nested objects.
  • Enum names persisted to disk become a compatibility contract; map them explicitly when names may change.
  • Sealed hierarchies are closed to known direct subclasses, but public API/module boundaries still need deliberate design.
  • Objects do not replace persistence; Android process death clears in-memory singleton state.

Interview questions​

What is the difference between init and a constructor?

The constructor defines how parameters enter object creation. init blocks execute initialization and validation as part of the primary-constructor path, in source order with property initializers.

Why are Kotlin classes final by default?

Inheritance must be intentional. Final-by-default prevents accidental overrides and makes behavior easier to reason about.

Data class versus sealed class?

A data class models one value shape. A sealed hierarchy models one of several known variants, each of which may contain different data.

Exercises​

  1. Create a Money class that rejects negative minor units.
  2. Model download states using a sealed interface.
  3. Demonstrate that data-class copy() is shallow with a mutable list.
  4. Replace a global mutable object with an injected state holder.
  5. Explain whether an enum name is safe to persist forever.
Architect takeaway

Choose a type form that prevents invalid states. Prefer constructor injection and composition, keep mutable ownership narrow, and remember that in-memory objects disappear on Android process death.