Android Architecture Evolution

📖 Concept

Android's architecture has evolved dramatically from the early MVC-like spaghetti to today's recommended architecture with Jetpack libraries.

Evolution timeline:

  1. 2008-2013: "God Activity" era — All logic in Activities. No separation of concerns. Rotation = data loss.
  2. 2014-2016: MVP (Model-View-Presenter) — Separated UI logic from business logic. But Presenters held View references → memory leaks on config changes.
  3. 2017-2019: MVVM + Architecture Components — Google released ViewModel, LiveData, Room, Navigation. Lifecycle-aware components eliminated most config-change bugs.
  4. 2020-present: Modern Architecture — Jetpack Compose, Kotlin Coroutines/Flow, Hilt DI, unidirectional data flow (UDF). Single-Activity architecture is the standard.

The Android OS Architecture Stack:

┌─────────────────────────────────────┐
│         Applications (Your App)     │
├─────────────────────────────────────┤
│    Android Framework (Java/Kotlin)  │
│  ActivityManager, WindowManager,    │
│  PackageManager, ContentProviders   │
├─────────────────────────────────────┤
│   Native Libraries    │ Android RT  │
│   (OpenGL, SQLite,    │ (ART, DEX)  │
│    WebKit, libc)      │             │
├─────────────────────────────────────┤
│    Hardware Abstraction Layer (HAL) │
├─────────────────────────────────────┤
│         Linux Kernel                │
│   (Drivers, Binder IPC, Memory)    │
└─────────────────────────────────────┘

Key internal components:

  • ART (Android Runtime): Replaced Dalvik in Android 5.0. Uses AOT + JIT compilation. Manages garbage collection with concurrent copying GC.
  • Binder IPC: Android's inter-process communication mechanism. All system service calls (ActivityManager, WindowManager) go through Binder.
  • Zygote: A warm process that forks to create new app processes. Pre-loads common classes and resources for fast app startup.

Why this matters at senior level: Understanding the stack helps you debug framework-level issues, optimize startup time, and make informed architecture decisions.

💻 Code Example

codeTap to expand ⛶
1// Modern Android Architecture — The Recommended Stack
2
3// 1. UI Layer (Compose)
4@Composable
5fun NoteListScreen(viewModel: NoteViewModel = hiltViewModel()) {
6 val uiState by viewModel.uiState.collectAsStateWithLifecycle()
7
8 when (val state = uiState) {
9 is UiState.Loading -> CircularProgressIndicator()
10 is UiState.Success -> NoteList(
11 notes = state.notes,
12 onDelete = viewModel::deleteNote
13 )
14 is UiState.Error -> ErrorMessage(state.message)
15 }
16}
17
18// 2. ViewModel Layer — Holds UI state, survives config changes
19@HiltViewModel
20class NoteViewModel @Inject constructor(
21 private val repository: NoteRepository
22) : ViewModel() {
23
24 val uiState: StateFlow<UiState> = repository.getNotes()
25 .map { UiState.Success(it) as UiState }
26 .catch { emit(UiState.Error(it.message ?: "Unknown error")) }
27 .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), UiState.Loading)
28
29 fun deleteNote(id: String) {
30 viewModelScope.launch { repository.delete(id) }
31 }
32}
33
34sealed interface UiState {
35 data object Loading : UiState
36 data class Success(val notes: List<Note>) : UiState
37 data class Error(val message: String) : UiState
38}
39
40// 3. Data Layer — Repository as single source of truth
41class NoteRepository @Inject constructor(
42 private val localDao: NoteDao,
43 private val remoteApi: NoteApi
44) {
45 fun getNotes(): Flow<List<Note>> = localDao.getAll()
46
47 suspend fun delete(id: String) {
48 localDao.delete(id)
49 try { remoteApi.delete(id) } catch (_: Exception) { /* queue for sync */ }
50 }
51}

🏋️ Practice Exercise

Practice:

  1. Draw the Android OS architecture stack from memory and label each layer
  2. Explain how ART differs from Dalvik — why did Google switch?
  3. Describe how Binder IPC works when you call startActivity()
  4. Explain what happens from the moment you tap an app icon to when the first frame renders
  5. Compare MVP, MVVM, and MVI — when would you choose each?
  6. Implement a simple MVVM screen with ViewModel + StateFlow + Compose
  7. Explain Zygote's role in app startup and how it impacts cold start time

⚠️ Common Mistakes

  • Putting business logic in Activities/Fragments — this died in 2017, use ViewModels

  • Not understanding Binder IPC — every system service call crosses process boundaries via Binder, and this has performance implications

  • Ignoring the architecture evolution context — knowing WHY patterns changed helps you make better decisions

  • Thinking Jetpack Compose replaces the entire architecture — Compose is just the UI layer, you still need ViewModel, Repository, etc.

💼 Interview Questions

🎤 Mock Interview

Mock interview is powered by AI for Android Architecture Evolution. Login to unlock this feature.