InsertKoinIO / koin

Koin - a pragmatic lightweight dependency injection framework for Kotlin & Kotlin Multiplatform
https://insert-koin.io
Apache License 2.0
9.08k stars 718 forks source link

Can we inject ViewModel Interfaces na #288

Closed alexandru-calinoiu closed 5 years ago

alexandru-calinoiu commented 6 years ago

Is your feature request related to a problem? Please describe. I don't want to inject the ViewModel implementations in my Activity/Fragment

Describe the solution you'd like Inject interfaces for my ViewModel

Describe alternatives you've considered So far my solution look like this

I will have an interface for my viewModel:

    interface ViewModel {
        val events: LiveData<ViewModelEvent>

        fun getLastWeather()
    }

I will have my ViewModel inherit the interface and livecycle.ViewModel:

class SplashViewModel : ViewModel(), SplashContract.ViewModel {

    override val events = SingleLiveEvent<ViewModelEvent>()

    override fun getLastWeather() {
    }
}

I will register my ViewModel like usual:

val weatherAppModule = module {
    viewModel { SplashViewModel(get(), get()) }
}

And use it in the Activity via this line:

    private val splashViewModel: SplashContract.ViewModel by viewModelByClass(SplashViewModel::class)

Target Koin project not sure

Linus-Weiss commented 5 years ago

Any updates on this? Thanks!

InsaneDoggo commented 5 years ago
viewModel { FooBarImpl() as FooBar }
erickok commented 5 years ago

@alexandru-calinoiu It looks like you ar enot using the Android ViewModel but instead define your own interface. In that case you don't need the viewModel {} definitions at all - a simple factory {} suffices. You inject them with by inject().

liminal commented 5 years ago

You can't use an interface for viewModel since unfortunately the base ViewModel is an abstract class and the ViewModelProvider.Factory methods require the provided viewmodel inherits from ViewModel.

But you can achieve the separation of interface and implementation by making the interface an abstract class instead.

// "interface"
abstract class FooViewModel {
    abstract val events: LiveData<ViewModelEvent>

    abstract fun getLastWeather()
}

// implementation
class FooViewModelImpl : FooViewModel() {
    override val events = SingleLiveEvent<ViewModelEvent>()

    override fun getLastWeather() {
    }
}

and then

viewModel<FooViewModel> { FooViewModelImpl() }

That is probably the closest you will get without some hacky workarounds

arnaudgiuliani commented 5 years ago

this last message is the best way to do that IMO

nijat-ahmadli commented 4 years ago

I found a way to do this, by overriding Koin extension functions. Please check my stackoverflow answer. Although I think abstract class is the way to go.