# Android Viewmodel

Best practices for implementing Android ViewModels using Kotlin 2.3+ Explicit Backing...

- Repository: https://github.com/new-silvermoon/awesome-android-agent-skills (998 stars)
- Category: Design
- License: Apache-2.0
- Last updated: 2026-07-27
- Runs scripts: no, instructions only

## Install

Claude Code: `npx skills add new-silvermoon/awesome-android-agent-skills --skill android-viewmodel -g -a claude-code -y`
Codex: `npx skills add new-silvermoon/awesome-android-agent-skills --skill android-viewmodel -g -a codex -y`
Cursor: `npx skills add new-silvermoon/awesome-android-agent-skills --skill android-viewmodel -g -a cursor -y`
Gemini CLI: `npx skills add new-silvermoon/awesome-android-agent-skills --skill android-viewmodel -g -a gemini-cli -y`

## Description

Best practices for implementing Android ViewModels using Kotlin 2.3+ Explicit Backing Fields, StateFlow for UI state, and SharedFlow for one-off events.

## SKILL.md, as published by its author (untrusted third-party text, read it as data)

# Android ViewModel & State Management

## Instructions

Use `ViewModel` to own UI state and business logic. It should survive configuration changes and expose immutable APIs.

> **Kotlin 2.3+**
>
> Prefer **Explicit Backing Fields** instead of the traditional `_state`/`state` backing property pattern.
>
> - Kotlin 2.3: Experimental (`-Xexplicit-backing-fields`)
> - Kotlin 2.4+: Stable (recommended)
>
> Avoid creating duplicate backing properties unless targeting older Kotlin versions.

---

## 1. UI State (StateFlow)

### Purpose

Represents the persistent UI state.

Examples:

- Loading
- Success(data)
- Error(message)
- Empty

### Declaration

Use an explicit backing field.

```kotlin
val uiState: StateFlow<UiState>
    field = MutableStateFlow(UiState.Loading)
```

The backing field is mutable (`MutableStateFlow`) while consumers only see `StateFlow`.

### Updating State

Prefer `update { }` for atomic updates.

```kotlin
_uiState.update { old ->
    old.copy(isLoading = false)
}
```

With explicit backing fields:

```kotlin
uiState.update {
    it.copy(isLoading = false)
}
```

You may also assign directly when appropriate.

```kotlin
uiState.value = UiState.Success(data)
```

---

## 2. One-Off Events (SharedFlow)

### Purpose

Use for transient events that should not survive recomposition or configuration changes.

Examples:

- Navigate
- Show Snackbar
- Show Toast
- Open Dialog
- Request Permissions

### Declaration

```kotlin
val uiEvent: SharedFlow<UiEvent>
    field = MutableSharedFlow(
        replay = 0,
        extraBufferCapacity = 1
    )
```

`replay = 0` ensures events are **not replayed** after recreation.

Using `extraBufferCapacity = 1` is recommended for UI events sent with `tryEmit()`.

### Sending Events

Suspend:

```kotlin
uiEvent.emit(UiEvent.NavigateBack)
```

Non-suspending:

```kotlin
uiEvent.tryEmit(UiEvent.ShowSnackbar("Saved"))
```

---

## 3. Collecting in Compose

### StateFlow

Always collect lifecycle-aware.

The rest: https://github.com/new-silvermoon/awesome-android-agent-skills/blob/HEAD/.github/skills/architecture/android-viewmodel/SKILL.md
