android-kotlin
ABOUTME: Android/Kotlin - Compose, architecture, testing, performance
ABOUTME: Kotlin 2.x, Compose 1.7+, type-safe navigation, Baseline Profiles
Android/Kotlin
Commands
./gradlew assembleDebug|assembleRelease|test|connectedAndroidTest|lint|ktlintFormat
./gradlew :feature:home:build # Module-specific
See: _AST_GREP.md (sg patterns) | _PATTERNS.md | source-control
Architecture
Clean Architecture Structure
feature/
├── data/repository/, datasource/local/, datasource/remote/
├── domain/model/, repository/ (interface), usecase/
└── presentation/screen/, viewmodel/
Use Cases
Single responsibility, orchestration here (NOT in ViewModel).
class SignInUseCase(private val auth: AuthRepository, private val user: UserRepository) {
suspend operator fun invoke(email: String, password: String): Result<User> {
val result = auth.signIn(email, password).getOrElse { return Result.failure(it) }
user.saveUserLocally(result)
return Result.success(result)
}
}
ViewModel Pattern
class FeedViewModel(private val getFeed: GetFeedUseCase) : ViewModel() {
private val _uiState = MutableStateFlow<FeedUiState>(FeedUiState.Loading)
val uiState = _uiState.asStateFlow()
private val _sideEffects = Channel<FeedSideEffect>(Channel.BUFFERED)
val sideEffects = _sideEffects.receiveAsFlow()
fun loadFeed() = viewModelScope.launch {
_uiState.value = FeedUiState.Loading
getFeed().onSuccess { _uiState.value = FeedUiState.Success(it) }
.onFailure { _uiState.value = FeedUiState.Error(it.message) }
}
}
sealed interface FeedUiState { /* Loading, Success, Error */ }
sealed interface FeedSideEffect { /* NavigateToDetail, ShowSnackbar */ }
Dependency Injection
| Aspect | Hilt | Koin |
|---|---|---|
| Type | Compile-time | Runtime |
| Build time | Slower | Faster |
| Error detection | Compile | Runtime |
| KMP support | No | Yes |
| Best for | Large/enterprise | Small-medium/KMP |
Hilt: @HiltAndroidApp, @AndroidEntryPoint, @HiltViewModel, @Inject constructor
Koin: module { }, single, factory, viewModelOf, koinViewModel()
See references/compose-patterns.md for setup examples.
Compose Essentials
State hoisting: Lift state to the caller, pass callbacks down.
@Composable
fun UserCard(user: User, onClick: () -> Unit, modifier: Modifier = Modifier) {
Card(onClick = onClick, modifier = modifier) { /* content */ }
}
State management:
remember { mutableStateOf() }, lost on config changerememberSaveable { mutableStateOf() }, survives config changederivedStateOf, computed state
Side effects: LaunchedEffect(key), DisposableEffect
Type-safe navigation: @Serializable routes (2.8.0+)
See references/compose-patterns.md for detailed examples.
Code Review Checklists
Architecture
- VMs don't chain use cases (orchestration in domain)
- VMs don't call repositories directly
- Use cases have single responsibility
- State immutable (use
copy()) - Side effects use Channel/SharedFlow (not StateFlow)
Compose
- State hoisted appropriately
-
remembervsrememberSaveablecorrect - Side effects use correct APIs
- Stable types for parameters
-
keyused in LazyColumn/LazyRow
Red Flags
| Critical | High |
|---|---|
| Network/DB on main thread | Use case chaining in VM |
| StateFlow for one-time events | Mutable state exposed from VM |
| Hardcoded strings in UI | Missing key in LazyColumn |
| Missing error handling | collectAsState vs collectAsStateWithLifecycle |
| R8 disabled in release |
Quick Reference
Kotlin 2.x features: Guard conditions (2.1), context parameters (2.2), K2 compiler benefits → references/kotlin-features.md
Compose patterns: State, side effects, navigation, image loading → references/compose-patterns.md
Networking & Data: Retrofit, Ktor, Room, DataStore → references/data-layer.md
Testing: Compose UI tests, ViewModel tests, snapshot tests → references/testing-patterns.md
Performance: R8, Baseline Profiles, Compose optimization → references/performance.md
Resources
Official: android.com/kotlin | compose | architecture | type-safe nav | baseline profiles
Libraries: Coil | Koin | Hilt | Retrofit | Ktor | Room
Testing: Compose testing | Paparazzi | Turbine