Implement Jetpack ViewModel in Compose Multiplatform (1/2)

Adrián Castro Torres
BestSecret Tech
Published in
3 min readMay 24, 2024

As Compose Multiplatform is fairly new, there are many things that we take for granted in the Android Development world that are still on their way to Multiplatform, for example, Jetpack ViewModel or Navigation which is still Experimental, but that doesn’t stop us from giving it a try, right?

In this first part of the article, you will learn how to replace Voyager’s Screen Model with Jetpack ViewModel, and in the upcoming second part, you will complete the integration by including Jetpack Navigation in your project.

So, let’s start by implementing the needed dependencies and continue with the implementation.

1- Implement dependencies:

The first thing we need to do is implement the compose navigation dependencies. If you would like to use the latest features of this library, you can check the latest available version here: https://mvnrepository.com/artifact/org.jetbrains.androidx.navigation/navigation-compose

commonMain.dependencies { 
implementation("org.jetbrains.androidx.navigation:navigation-compose:"2.8.0-alpha02")
}

2- Refactor your screen models:

We will continue by replacing the screen models with the Jetpack ViewModel, from this:

class RandomViewModel: ScreenModel, KoinComponent { }

To this:

class RandomViewModel: ViewModel(), KoinComponent { }

If you were using StateScreenModel to handle your UI state, please stay until the end of the article to learn how to take care of that.

3- Refactor your screen model instance:

After modifying the ViewModel type, we also need to change its instance in the UI, so if you had something like this:

val viewModel = rememberScreenModel { RandomViewModel() }

You can use this way of instantiating the Jetpack ViewModel:

val viewModel = viewModel { RandomViewModel() }

4- Modify your screenModelScope usage:

It is possible that some functions in your view models needed a coroutine to be launched, if that’s the case, you can replace this:

screenModelScope.launch() { yourFunction() }

With this:

viewModelScope.launch() { yourFunction() }

Extra: Migrate StateScreenModel

Also, you might be using your ScreenModel with the coroutines integration to make the most out of Voyager, here is how to migrate it.

From this:

class RandomScreenModel : StateScreenModel<State>(State.Idle) { 
fun loadSomething() {
mutableState.value = State.Loading
}
}

To this:

class RandomScreenModel : ViewModel() { 
private val _state: MutableStateFlow<State> = MutableStateFlow(State.Idle)
val state: StateFlow<State> = _state

fun loadSomething() {
_state.value = State.Loading
}
}

Now you can modify the state inside the view model using _state and expose it to the UI with the public state.

Repeat these steps with all the screen models, and that’s it!

Photo by Ray Hennessy on Unsplash

If you have any doubt, feel free to contact me on LinkedIn: https://www.linkedin.com/in/adrianct/

In the next article, I will show you how to replace the voyager navigation with the newly supported compose navigation for Compose Multiplatform. Until then, see you!

--

--