The Android team’s recommended architecture has crystallised in 2024: a unidirectional data flow pattern combining Hilt for dependency injection, Room + StateFlow for the data layer, ViewModel for the presentation layer, and Jetpack Compose for the UI. This stack is opinionated, testable, and the subject of all new official Android documentation.
The Layered Architecture
UI Layer → Composables + ViewModel
Domain Layer → Use Cases (optional, for complex apps)
Data Layer → Repository + Room / Network (Retrofit)
ViewModel with StateFlow
StateFlow replaces LiveData for exposing UI state from the ViewModel. It is a Kotlin-native, lifecycle-aware observable that integrates cleanly with Compose:
data class HomeUiState(
val posts: List<Post> = emptyList(),
val isLoading: Boolean = false,
val error: String? = null,
)
@HiltViewModel
class HomeViewModel @Inject constructor(
private val postRepository: PostRepository
) : ViewModel() {
private val _uiState = MutableStateFlow(HomeUiState(isLoading = true))
val uiState: StateFlow<HomeUiState> = _uiState.asStateFlow()
init {
viewModelScope.launch {
postRepository.getPosts()
.catch { e -> _uiState.update { it.copy(error = e.message, isLoading = false) } }
.collect { posts -> _uiState.update { it.copy(posts = posts, isLoading = false) } }
}
}
}
Hilt Dependency Injection
// Application
@HiltAndroidApp
class MyApplication : Application()
// Module
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Provides @Singleton
fun provideDatabase(@ApplicationContext ctx: Context) =
Room.databaseBuilder(ctx, AppDatabase::class.java, "app.db").build()
}
// ViewModel auto-wired with @HiltViewModel + @Inject
Compose UI Connected to StateFlow
@Composable
fun HomeScreen(vm: HomeViewModel = hiltViewModel()) {
val uiState by vm.uiState.collectAsStateWithLifecycle()
when {
uiState.isLoading -> LoadingIndicator()
uiState.error != null -> ErrorMessage(uiState.error!!)
else -> PostList(uiState.posts)
}
}
Navigation Compose
Use navigation-compose for type-safe navigation between screens. Define your NavGraph in one place and navigate using type-safe route objects (stable in Navigation 2.7+ with the new serialization-based API).
Testing the Stack
- Unit test ViewModels with
UnconfinedTestDispatcherandTurbinefor StateFlow - Test the Repository with an in-memory Room database
- UI test Composables with
composeTestRule.setContent { }
The 2024 Android architecture stack is mature, well-documented, and backed by years of production experience. If you are starting a new Android project, adopt it wholesale — the investment in structure pays back on the first feature you need to refactor.