android-kmp-viewmodellisted
Install: claude install-skill lenorebreakneck630/claude-zero-to-hero-android-KMP
# KMP ViewModel
## Strategy
Keep `ViewModel` class on Android (it owns `viewModelScope`). Move all **state logic** to a platform-agnostic `Presenter` or `CommonViewModel` in `commonMain` that takes an explicit `CoroutineScope`.
## CommonViewModel (`commonMain`)
```kotlin
// commonMain — core:domain or feature module
abstract class CommonViewModel {
private val viewModelScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
protected fun launch(block: suspend CoroutineScope.() -> Unit): Job =
viewModelScope.launch(block = block)
open fun onCleared() {
viewModelScope.cancel()
}
}
```
## Android ViewModel wraps it
```kotlin
// androidMain
class TaskListViewModel(
private val getTasks: GetTasksUseCase,
) : ViewModel() {
private val _state = MutableStateFlow(TaskListState())
val state: StateFlow<TaskListState> = _state.asStateFlow()
init {
viewModelScope.launch {
getTasks().collect { tasks ->
_state.update { it.copy(tasks = tasks) }
}
}
}
}
```
## iOS Swift wrapper (StateFlow → Combine)
```kotlin
// iosMain — thin wrapper so Swift can observe
class TaskListIosViewModel(
private val getTasks: GetTasksUseCase,
) : CommonViewModel() {
private val _state = MutableStateFlow(TaskListState())
val state: StateFlow<TaskListState> = _state.asStateFlow()
init {
launch {
getTasks().collect { tasks ->
_state.update { i