Koin Android 3.3.0 - Easier, Better, Stronger with ViewModels

Hello Koin users 👋
We are happy to announce the release of koin-android
and koin-androidx-compose
in version 3.3.0. This version focus on ViewModel API updates.
In this article, let's take a tour of ViewModel features and how it has been improved in this new version. You can take a look at the Github milestone gathering the solved issues. The changelog is available.
Check the setup page to help you update your Gradle configuration: https://insert-koin.io/docs/setup/koin

Androidx Lifecycle - 2.5.1
Since 2018, the Android ViewModel library has evolved bringing new features over time. ViewModel is in touch with many topics like Lifecycle, SavedStateHandle, LiveData, Flow and other Android components.
The previous version of koin-android
was based on 2.4.1. One of the main issues was about injecting the right data in SavedStateHandle
objects and keeping it in state restoration. Also, the previous State ViewModel Factory could lead to some testing issues.
Koin is solving all of this, as it's now based on the latest stable API, aka androidx-lifecycle
2.5.1. You can look at the official Android release page to see all the latest changes from the Android API side: https://developer.android.com/jetpack/androidx/releases/lifecycle#version_25_2
Keeping it Simple
As the main mission of Koin, we let you assemble your components in a fun and simple way. Â We care about having the smoothest developer experience possible. For ViewModel, we want to sharpen the experience we have built since the beginning.
Declare your ViewModel in one line, in a Koin module:
module {
// Classic DSL
viewModel { DetailViewModel(get(), get()) }
// or Constructor DSL
viewModelOf(::DetailViewModel)
}
From any Activity or Fragment, use the by viewModel()
function:
class DetailActivity : AppCompatActivity() {
// Inject DetailViewModel lazily
val detailViewModel: DetailViewModel by viewModel()
}
That's it! Koin is creating the right ViewModel factory to be bound to your ViewModel instance. In a nutshell, you just need to declare your ViewModel class as a viewModel
definition in Koin and we take care of everything.
Shared ViewModel with Activity
The other ability behind the ViewModel, is the ability to share the same ViewModel instance between one Activity and its Fragments.
The function proposed previously in Fragment was the sharedViewModel()
function, confusing a bit the origin of the shared instance.
We propose today to get closer to the Google Android naming and replace sharedViewModel()
with activityViewModel()
. This seems clearer to understand: the instance is shared and backed by the underlying Activity:
class MyActivity : AppCompatActivity() {
// Main instance
val DetailViewModel : DetailViewModel by viewModel()
}
class FragmentOne : Fragment() {
// Shared instance
val DetailViewModel : DetailViewModel by activityViewModel()
}
class FragmentTwo : Fragment() {
// Shared instance
val DetailViewModel : DetailViewModel by activityViewModel()
}
Note that the by sharedVieweModel()
 function is now deprecated.
Injecting SavedStateHandle - The (new) Easy Way
Here we are. One of the main reasons to upgrade to koin-android
3.3.0. Previously, to be able to inject a ViewModel class constructor with an SavedStateHandle
argument, you had to use one of the by stateViewModel()
 functions.
Even more, we were rallying injected parameters to help inject the bundle arguments from your Activity/Fragment to your ViewModel. Well, it all ended in very complex API usage. The 2.5.1 Androidx Lifecycle release helps us bring everything for you and forget about the previous nightmarish functions.
Here is how you can deal with SavedStateHandle
argument in koin-android
3.3.0. Let's take a ViewModel class:
class MyStatefulViewModel(val handle: SavedStateHandle) : ViewModel()
Just declare it as a "regular" ViewModel:
module {
// Classic DSL
viewModel { MyStatefulViewModel(get()) }
// or Constructor DSL
viewModelOf(::MyStatefulViewModel)
}
Now, you can retrieve your ViewModel instance with just the by viewModel()
function:
class MyActivity : AppCompatActivity() {
val myStatefulViewModel: MyStatefulViewModel by viewModel()
}
That's it! You are now ready to use your SavedStateHandle
data in your ViewModel class. No need for extra complexity anymore.
Injected Parameters & Other Advanced Usages
We kept all the capacity of the Koin ViewModel API to let you use what you need. You can still use injected parameters, to help you create your ViewModel instance.
Let's declare a ViewModel that uses an Id as injected parameter:
class MyIdViewModel(val id: String) : ViewModel()
Let's declare it in a Koin module:
module {
viewModel {(id : String) -> MyIdViewModel(id)}
// or
viewModelof(::MyIdViewModel)
}
Now, let's pass our id to our ViewModel:
class MyActivity : AppCompatActivity() {
val myId : String = "..."
val myIdViewModel: MyIdViewModel by viewModel{parametersOf(myId)}
}
Note that the injected parameters will be used once, at first ViewModel instance creation. After that, when you request an already existing ViewModel instance, injected parameters won't be reevaluated.
If you need to have hands-on Tag, ViewModelStoreOwner ... all are available in the by viewModel()
API. Also, you can access the viewModelForClass()
function, to let your setup some generics. Â
Android Jetpack Compose Ready
All the Androidx Lifecycle 2.5.1 update has been ported to the koin-androidx-compose
project. You benefit directly from all the improvements above.
For Jetpack Compose, we are also opening a new function with a more explicit naming: the koinViewModel()
function:
@Composable
fun AuthorRoute(
onBackClick: () -> Unit,
modifier: Modifier = Modifier,
viewModel: AuthorViewModel = koinViewModel(),
) {
// ...
}
Just declare it in a Koin module:
val authorKoinModule = module {
viewModelOf(::AuthorViewModel)
}
Note that we are also using it here with a SavedStateHandle
parameter:
class AuthorViewModel constructor(
savedStateHandle: SavedStateHandle,
// ...
) : ViewModel()
Stay tuned for our next article about the NowInAndroid app with Koin.
We hope you'll enjoy this new update. Feel free to give your feedback on Twitter: Â @insertkoin_io
Do not forget to subscribe to our blog to be sure to see all our fresh news!
See you 👋