https://kotlinlang.org logo
Title
e

Enrico Saggiorato

02/07/2022, 6:10 PM
Hi! I'm new to kotlin and compose and I have some doubts 🙂 I know that when using Compose in Android the screen state and application state are managed through the ViewModel API. Is ViewModel Android-specific or is it suitable also for Compose Desktop? And eventually, what are we supposed to use to manage app-scoped state instead?
e

Enrico Saggiorato

02/07/2022, 6:22 PM
I don't get what you mean by saying "pure-Kotlin concepts like Flow", sorry. I guess it's a language feature that I don't know, can you link me some resources please?
Anyway, just to make sure I understood, application-wide state is just a regular state (called with
remember
) in the application function instead of in one of my components, right?
d

David W

02/07/2022, 6:40 PM
application-wide state is just a regular state (called with
remember
) in the application function instead of in one of my components, right? (edited)
not necessarily even with
remember
, although you could do that. i think they just mean a variable that's accessible from anywhere in the application
like, you could just do
companion object { val appState: ... }
in your Application class
c

Casey Brooks

02/07/2022, 6:48 PM
Flow
is basically the Kotlin implementation of a reactive stream (like RxJava Observables), but built on coroutines. Compose is built on top of Coroutines as well, and integrates very nicely with Flows. Here's a very simple example. See how the
MyViewModel
is just a normal class, no super class necessary, and the "lifecycle" of the ViewModel is controlled by the composition, and you'd use it in much the same way as you would a normal Android ViewModel.
class MyViewModel(
    val viewModelScope: CoroutineScope
) {
    data class State(
        val count: Int = 0
    )

    private val _state = MutableStateFlow(State())
    val state: StateFlow<State> get() = _state.asStateFlow()

    fun increment() {
        viewModelScope.launch { 
            _state.update { it.copy(count = it.count + 1) }
        }
    }

    fun decrement() {
        viewModelScope.launch { 
            _state.update { it.copy(count = it.count - 1) }
        }
    }
}

@Composable
fun MyApp() {
    val viewModelScope = rememberCoroutineScope()
    val viewModel = remember(viewModelScope) { MyViewModel(viewModelScope) }
    val vmState by viewModel.state.collectAsState()

    MyAppUi(
        state = vmState,
        onIncrement = { viewModel.increment() },
        onDecrement = { viewModel.decrement() },
    )
}

@Composable
fun MyAppUi(
    state: MyViewModel.State,
    onIncrement: ()->Unit,
    onDecrement: ()->Unit,
) {
    // ...
}
👏 4
g

gildor

02/10/2022, 11:57 PM
Androidx ViewModel created specifically to survive activity recreation on configuration change, so it purely Android specific use case. You don't have activities on desktop and configuration changes too, so what is the point of Androidx ViewModels on desktop?
d

David W

02/10/2022, 11:59 PM
Possibly simply to separate logic from the view, rather than anything lifecycle-related
g

gildor

02/11/2022, 12:01 AM
But to separate logic from the view you can use any ViewModel, you don't need androidx.lifecycle.ViewModel, any class with appropriate lifecycle (per component, per application) will work
Even on Android with pure compose application it doesn't look that you need Androidx ViewModels, you can disable configuration change on your only activity and that's all, you can use any own ViewModel (or other architecture pattern) to separate business logic from UI.