简体   繁体   中英

How to provide ViewModel that has interface via Koin

I have the following ViewModel setup:

interface FooViewModel {}

class FooViewModelImpl: ViewModel(), FooViewModel {}

and I want to provide it via Koin like this:

viewModel<FooViewModel> { FooViewModelImpl() }

It doesn't work because Koin expects ViewModel instead of FooViewModel in the definition and I don't want to make my FooViewModel an abstract class that extends from ViewModel.

Is there a way I can do this via Koin?

The only way I got it working was to override Koin extension function and enforce qualifier:

  • Override Koin Module extension function to drop ViewModel from its generics definition:
inline fun <reified T> Module.customViewModel(
    qualifier: Qualifier? = null,
    noinline definition: Definition<T>
): BeanDefinition<T> {
    return viewModel(qualifier ?: named(T::class.java.name), definition = definition)
}

inline fun <reified T> Module.viewModel(
    qualifier: Qualifier? = null,
    override: Boolean = false,
    noinline definition: Definition<T>
): BeanDefinition<T> {
    val beanDefinition = factory(qualifier, override, definition)
    beanDefinition.setIsViewModel()
    return beanDefinition
}
  • Override Koin LifecycleOwner extension functions same way:
inline fun <reified T> LifecycleOwner.customViewModel(
    qualifier: Qualifier? = null,
    noinline parameters: ParametersDefinition? = null
): Lazy<T> = lazy { getViewModel<ViewModel>(qualifier ?: named(T::class.java.name), parameters) as T }

inline fun <reified T> LifecycleOwner.getCoreViewModel(
    qualifier: Qualifier? = null,
    noinline parameters: ParametersDefinition? = null
): T = getViewModel<ViewModel>(qualifier ?: named(T::class.java.name), parameters) as T

Then you can provide FooViewModel as

viewModel<FooViewModel> { FooViewModelImpl() }

and inject it as:

private val viewModel: FooViewModel by customViewModel()
// or
val viewModel: FooViewModel = getCustomViewModel()

Although this is possible I don't think it is a good idea, just wanted to share my findings. The best way would be to use abstract class (which inherits from Android ViewModel ) instead of an interface.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM