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:
- 2008-2013: "God Activity" era — All logic in Activities. No separation of concerns. Rotation = data loss.
- 2014-2016: MVP (Model-View-Presenter) — Separated UI logic from business logic. But Presenters held View references → memory leaks on config changes.
- 2017-2019: MVVM + Architecture Components — Google released ViewModel, LiveData, Room, Navigation. Lifecycle-aware components eliminated most config-change bugs.
- 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
1// Modern Android Architecture — The Recommended Stack23// 1. UI Layer (Compose)4@Composable5fun NoteListScreen(viewModel: NoteViewModel = hiltViewModel()) {6 val uiState by viewModel.uiState.collectAsStateWithLifecycle()78 when (val state = uiState) {9 is UiState.Loading -> CircularProgressIndicator()10 is UiState.Success -> NoteList(11 notes = state.notes,12 onDelete = viewModel::deleteNote13 )14 is UiState.Error -> ErrorMessage(state.message)15 }16}1718// 2. ViewModel Layer — Holds UI state, survives config changes19@HiltViewModel20class NoteViewModel @Inject constructor(21 private val repository: NoteRepository22) : ViewModel() {2324 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)2829 fun deleteNote(id: String) {30 viewModelScope.launch { repository.delete(id) }31 }32}3334sealed interface UiState {35 data object Loading : UiState36 data class Success(val notes: List<Note>) : UiState37 data class Error(val message: String) : UiState38}3940// 3. Data Layer — Repository as single source of truth41class NoteRepository @Inject constructor(42 private val localDao: NoteDao,43 private val remoteApi: NoteApi44) {45 fun getNotes(): Flow<List<Note>> = localDao.getAll()4647 suspend fun delete(id: String) {48 localDao.delete(id)49 try { remoteApi.delete(id) } catch (_: Exception) { /* queue for sync */ }50 }51}
🏋️ Practice Exercise
Practice:
- Draw the Android OS architecture stack from memory and label each layer
- Explain how ART differs from Dalvik — why did Google switch?
- Describe how Binder IPC works when you call startActivity()
- Explain what happens from the moment you tap an app icon to when the first frame renders
- Compare MVP, MVVM, and MVI — when would you choose each?
- Implement a simple MVVM screen with ViewModel + StateFlow + Compose
- 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.