使用Dagger 2 + Kotlin + ViewModel注入ViewModel [英] Inject ViewModel using Dagger 2 + Kotlin + ViewModel

查看:444
本文介绍了使用Dagger 2 + Kotlin + ViewModel注入ViewModel的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

class SlideshowViewModel : ViewModel() {

@Inject lateinit var mediaItemRepository : MediaItemRepository

fun init() {
    What goes here?
}

所以我正在尝试学习Dagger2,以便可以使我的应用程序更具可测试性.问题是,我已经集成了Kotlin并正在开发Android Architectural组件.我知道最好使用构造函数注入,但这对于ViewModel是不可能的.相反,我可以使用lateinit进行注入,但是我不知所措,想知道如何进行注入.

So I'm trying to learn Dagger2 so I can make my apps more testable. Problem is, I've already integrated Kotlin and am working on the Android Architectural components. I understand that constructor injection is preferable but this isn't possible with ViewModel. Instead, I can use lateinit in order to inject but I'm at a loss to figure out how to inject.

是否需要为SlideshowViewModel创建一个Component,然后注入它?还是使用Application组件?

Do I need to create a Component for SlideshowViewModel, then inject it? Or do I use the Application component?

等级:

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'

kapt { 
    generateStubs = true
}
dependencies {
    compile "com.google.dagger:dagger:2.8"
    annotationProcessor "com.google.dagger:dagger-compiler:2.8"
    provided 'javax.annotation:jsr250-api:1.0'
    compile 'javax.inject:javax.inject:1'
}

应用程序组件

@ApplicationScope
@Component (modules = PersistenceModule.class)
public interface ApplicationComponent {

    void injectBaseApplication(BaseApplication baseApplication);
}

BaseApplication

BaseApplication

    private static ApplicationComponent component;

    @Override
    public void onCreate() {
        super.onCreate();

        component = DaggerApplicationComponent
                .builder()
                .contextModule(new ContextModule(this))
                .build();
        component.injectBaseApplication(this);
    }

    public static ApplicationComponent getComponent() {
        return component;
    }

推荐答案

您可以为ViewModel启用构造函数注入.您可以签出

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)

这是在Kotlin中执行类似操作的方法:

Here is how to do a similar thing in Kotlin:

添加ViewModelKey注释:

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<out ViewModel>)

添加ViewModelFactory:

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<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>
) : ViewModelProvider.Factory {

    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        var creator: Provider<out ViewModel>? = 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)
        }
    }
}

添加ViewModelModule:

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
}

在您的组件中注册ViewModelModule

Register your ViewModelModule in your component

在活动中插入ViewModelProvider.Factory:

Inject ViewModelProvider.Factory in your activity:

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

将您的modelFactory传递给每个ViewModelProviders.of方法:

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

这篇关于使用Dagger 2 + Kotlin + ViewModel注入ViewModel的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆