android-compose-uilisted
Install: claude install-skill lenorebreakneck630/claude-zero-to-hero-android-KMP
# Android / KMP Compose UI Patterns
## Core Principle
The UI is dumb. Composables render state and forward user actions — nothing more. All state lives in the ViewModel. All logic lives in the ViewModel, domain, or data layer. Compose code should contain zero business logic, zero data transformation, and minimal side effects.
---
## Stability & Recomposition
Strong skipping mode is enabled by default in modern Compose — no explicit opt-in needed.
Only annotate a state data class with `@Stable` when it contains fields the Compose compiler considers unstable (e.g., `List`, `Map`, `Set`, interfaces, or abstract types). If all fields are primitive types, `String`, or other stable types, no annotation is needed.
```kotlin
// Needs @Stable — contains a List (unstable by default)
@Stable
data class NoteListState(
val notes: List<NoteUi> = emptyList(),
val isLoading: Boolean = false
)
// No annotation needed — all fields are stable
data class NoteDetailState(
val title: String = "",
val body: String = "",
val isSaving: Boolean = false
)
```
---
## State Ownership
All state lives in the ViewModel. Do not use `remember` or `rememberSaveable` for application state — that belongs in the ViewModel's `StateFlow` and is surfaced via `collectAsStateWithLifecycle()`.
The only exception is Compose-internal state that the framework requires you to hold in composition, such as `LazyListState`, `ScrollState`, or `PagerState`. For these, use `remember*` as needed: