'Koin 3.2/Compose - injecting an activity-scoped viewmodel from a composable
I have scoped a viewmodel to an activity like this:
scope<MyActivity> {
scoped<UseCase1> { UseCase1Impl(get()) }
scoped<UseCase2> { UseCase2Impl(get()) }
viewModel { parameters -> MyViewModel(parameters.get(), get(), get()) }
}
In my activity I cannot access the viewmodel inside a composable with this call:
setContent {
val viewModel: MyViewModel by org.koin.androidx.compose.viewModel {
ParametersHolder(mutableListOf("1"))
}
viewModel.doSomething()
}
UNLESS I also do this outside the composable:
private val viewModel by viewModel<CameraNameViewModel> { parametersOf("1") }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel // If I comment this, it crashes
// setContent etc
}
The error is
Caused by: org.koin.core.error.NoBeanDefFoundException: |- No definition found for class:'com.anonymised.path.to.MyViewModel'. Check your definitions!
Deep-diving with the debugger, it looks like the activities mViewmodelStore property is only populated when accessed outside the composable. I do have a workaround in that I can just inject every viewmodel in my top-level activity, but it doesn't seem right basically injecting it twice.
Solution 1:[1]
So you have two options:
Option 1: If your both your activity and your composable need the viewModel:
Inject your
viewModel
into your activity like you already havejust pass the
viewModel
to your composableclass YourActivity : AppCompatActivity() { private val viewModel by viewModel<CameraNameViewModel> { parametersOf("1") } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { YourComposeScreen(viewModel) } } } @Composable fun YourComposeScreen(viewModel: CameraNameViewModel){ /*your composable */ }
Option 2: you only need your viewModel in your composable:
don't inject the viewModel into your composable
just use koins Compose-Syntax to inject the
viewModel
to your composableclass YourActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { YourComposeScreen() // <- we do not need any parameter here } } } @Composable fun YourComposeScreen( viewModel: CameraNameViewModel = getViewModel(parameters = { parametersOf("1") }) ){ /*your composable */ }
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | m.reiter |