android - 使用 Dagger 2 + Kotlin + ViewModel 注入(inject) ViewModel

标签 android dependency-injection kotlin dagger-2 dagger

class SlideshowViewModel : ViewModel() {

@Inject lateinit var mediaItemRepository : MediaItemRepository

fun init() {
    What goes here?
}

所以我正在尝试学习 Dagger2,以便让我的应用更易于测试。问题是,我已经集成了 Kotlin 并且正在开发 Android 架构组件。我知道构造函数注入(inject)更可取,但这对于 ViewModel 是不可能的。相反,我可以使用 lateinit 来注入(inject),但我不知道如何注入(inject)。

我需要为SlideshowViewModel创建一个Component,然后注入(inject)吗?还是我使用 Application 组件?

分级:

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);
}

基础应用

    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 启用构造函数注入(inject)。您可以查看Google samples看看如何在 Java 中做到这一点。 (更新:看起来他们将项目转换为 Kotlin,所以这个 URL 不再有效)

下面是如何在 Kotlin 中做类似的事情:

添加 ViewModelKey 注解:

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:

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:

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

在您的 Activity 中注入(inject) ViewModelProvider.Factory:

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

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

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

这是包含所有必需更改的示例提交:Support constructor injection for view models

关于android - 使用 Dagger 2 + Kotlin + ViewModel 注入(inject) ViewModel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44712248/

相关文章:

android - 如何在 webview 滚动期间隐藏/显示底部导航 View

android - 在它们之间有分隔线的 TextView

java - Android fragment 错误 : No view found for id 0x7f08009e (com. example.myapplication:id/preferenceFragment) fragment

android - 如何使用 kotlin 在 Android Studio 上正确设置 SwipeRefreshLayout?

android - 使用 safeargs 我得到 "required Bundle found Bundle?"

android - 在android中存储 ListView 位置

android - 单击列表项时如何将单选按钮设置为选中

javascript - RequireJS - 导出一组函数

c# - 在简单注入(inject)器中注册具有构造函数参数的泛型类型

java - 是否可以使用 HashMultimap 创建 spring bean?