Inject ViewModel using Dagger 2 + Kotlin + ViewModel

后端 未结 6 1359
-上瘾入骨i
-上瘾入骨i 2021-02-07 07:07
class SlideshowViewModel : ViewModel() {

@Inject lateinit var mediaItemRepository : MediaItemRepository

fun init() {
    What goes here?
}

So I\'m tr

6条回答
  •  醉梦人生
    2021-02-07 07:57

    You can enable constructor injection for your ViewModels. You can check out Google samples to see how to do it in Java. (Update: looks like they converted the project to Kotlin so this URL no longer works)

    Here is how to do a similar thing in Kotlin:

    Add ViewModelKey annotation:

    import android.arch.lifecycle.ViewModel
    
    import java.lang.annotation.Documented
    import java.lang.annotation.ElementType
    import java.lang.annotation.Retention
    import java.lang.annotation.RetentionPolicy
    import java.lang.annotation.Target
    
    import dagger.MapKey
    import kotlin.reflect.KClass
    
    @Suppress("DEPRECATED_JAVA_ANNOTATION")
    @Documented
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @MapKey
    internal annotation class ViewModelKey(val value: KClass)
    

    Add ViewModelFactory:

    import android.arch.lifecycle.ViewModel
    import android.arch.lifecycle.ViewModelProvider
    
    import javax.inject.Inject
    import javax.inject.Provider
    import javax.inject.Singleton
    
    @Singleton
    class ViewModelFactory @Inject constructor(
        private val creators: Map, @JvmSuppressWildcards Provider>
    ) : ViewModelProvider.Factory {
    
        @Suppress("UNCHECKED_CAST")
        override fun  create(modelClass: Class): T {
            var creator: Provider? = creators[modelClass]
    
            if (creator == null) {
                for ((key, value) in creators) {
                    if (modelClass.isAssignableFrom(key)) {
                        creator = value
                        break
                    }
                }
            }
    
            if (creator == null) {
                throw IllegalArgumentException("unknown model class " + modelClass)
            }
    
            try {
                return creator.get() as T
            } catch (e: Exception) {
                throw RuntimeException(e)
            }
        }
    }
    

    Add ViewModelModule:

    import dagger.Module
    import android.arch.lifecycle.ViewModel
    import dagger.multibindings.IntoMap
    import dagger.Binds
    import android.arch.lifecycle.ViewModelProvider
    import com.bubelov.coins.ui.viewmodel.EditPlaceViewModel
    
    @Module
    abstract class ViewModelModule {
        @Binds
        @IntoMap
        @ViewModelKey(EditPlaceViewModel::class) // PROVIDE YOUR OWN MODELS HERE
        internal abstract fun bindEditPlaceViewModel(editPlaceViewModel: EditPlaceViewModel): ViewModel
    
        @Binds
        internal abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
    }
    

    Register your ViewModelModule in your component

    Inject ViewModelProvider.Factory in your activity:

    @Inject lateinit var modelFactory: ViewModelProvider.Factory
    private lateinit var model: EditPlaceViewModel
    

    Pass your modelFactory to each ViewModelProviders.of method:

    model = ViewModelProviders.of(this, modelFactory)[EditPlaceViewModel::class.java]
    

    Here is the sample commit which contains all of the required changes: Support constructor injection for view models

提交回复
热议问题