Android Kotlin匕首2 ViewModel注入错误

时间:2017-11-02 14:10:51

标签: android kotlin viewmodel dagger-2

我试图在我的项目中使用arch android库中的新ViewModel

我在github上研究了很多示例项目。最后,我想在我的项目中实现这个架构,但我无法构建它。

Gradle控制台:

....AppComponent.java:6: error: [dagger.android.AndroidInjector.inject(T)] kibar.app.ui.fragment.HomeFragmentViewModel cannot be provided without an @Inject constructor or from an @Provides-annotated method.

e: public abstract interface AppComponent {
e:                 ^
e:       kibar.app.ui.fragment.vpresenter.home.HomeFragmentViewModel is injected at
e:           kibar.core.di.ViewModelModule.bindHomeViewModel(model)
e:       java.util.Map<java.lang.Class<? extends android.arch.lifecycle.ViewModel>,javax.inject.Provider<android.arch.lifecycle.ViewModel>> is injected at
e:           kibar.core.di.viewmodel.ViewModelFactory.<init>(creators)
e:       kibar.core.di.viewmodel.ViewModelFactory is injected at
e:           kibar.app.ui.fragment.HomeFragment.viewModelFactory
e:       kibar.app.ui.fragment.HomeFragment is injected at
e:           dagger.android.AndroidInjector.inject(arg0)
e: java.lang.IllegalStateException: failed to analyze: org.jetbrains.kotlin.kapt3.diagnostic.KaptError: Error while annotation processing
    at org.jetbrains.kotlin.analyzer.AnalysisResult.throwIfError(AnalysisResult.kt:57)
    at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules(KotlinToJVMBytecodeCompiler.kt:138)
    at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:154)
    at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:58)
    at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.java:103)
    at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.java:51)
    at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:92)
    ...
    ...
    ...

代码:

class App : Application(), HasActivityInjector {

    @field:Inject lateinit var component: AppComponent
    @field:Inject lateinit var injector: DispatchingAndroidInjector<Activity>

    override fun activityInjector() = injector
    override fun onCreate() {
        super.onCreate();

        DaggerAppComponent.builder()
                .appModule(AppModule(this))
                .build()
                .apply { inject(this@App); component = this }
                .inject(this)
    }

}

@AppScope
@Component(
        modules = arrayOf(
                AndroidSupportInjectionModule::class,
                AppModule::class,
                ActivityModule::class,
                ViewModelModule::class,
                DatabaseModule::class)
)
interface AppComponent {

    interface Builder {
        @BindsInstance
        fun application(app: App): Builder

        fun build(): AppComponent
    }

    fun inject(application: App)

}

@Module
class AppModule(private val application: Application) {

    @Provides
    @AppScope
    fun provideApplication(): Application = application

    @Provides
    @AppScope
    @ApplicationContext
    fun provideContext(): Context = application.applicationContext!!

}

@Module
abstract class ActivityModule {

    @ContributesAndroidInjector(modules = arrayOf(FragmentModule::class))
    abstract fun bindHomeActivity(): HomeActivity

}

@Module(includes = arrayOf(AppModule::class))
class DatabaseModule {

    @AppScope
    @Provides
    fun provideDatabase(@ApplicationContext context: Context): RoomDatabase =
            Room.databaseBuilder(context, RoomDatabase::class.java, RoomDatabase.CONS.NAME)
                .allowMainThreadQueries()
                .build()

}

@Module
abstract class FragmentModule {

    @ContributesAndroidInjector
    abstract fun provideHomeFragment(): HomeFragment

}

@Module
abstract class ViewModelModule {

    @Binds
    @IntoMap
    @ViewModelKey(HomeFragmentViewModel::class)
    abstract fun bindHomeViewModel(model: HomeFragmentViewModel): ViewModel

    @Binds
    abstract fun bindAppViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory

}

@AppScope
class ViewModelFactory @Inject
constructor(private val creators: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>) : ViewModelProvider.Factory {

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

}

@MustBeDocumented
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
internal annotation class ViewModelKey(val value: KClass<out ViewModel>)

@Scope
@Retention(AnnotationRetention.RUNTIME)
annotation class AppScope

@Qualifier
@Retention(AnnotationRetention.RUNTIME)
annotation class ApplicationContext

class HomeActivity : AppCompatActivity(), HasSupportFragmentInjector{

    @Inject lateinit var androidInjector: DispatchingAndroidInjector<Fragment>
    override fun supportFragmentInjector() = androidInjector

    override fun onCreate(savedInstanceState: Bundle?) {
        AndroidInjection.inject(this)
        super.onCreate(savedInstanceState) 
        ...
    }

    fun openHomeFragment() {
        //to make a quick experiment
        supportFragmentManager.beginTransaction()
                .replace(R.id.fragmentLayout, HomeFragment(),"HomeFragment")
                .addToBackStack(null)
                .commit();
    }

}

class HomeFragment : Fragment(){

    @Inject lateinit var viewModelFactory: ViewModelFactory

    //@Inject
    val viewModel by lazy { ViewModelProviders.of(this, viewModelFactory).get(HomeFragmentViewModel::class.java) }

    override fun onAttach(context: Context?) {
        AndroidSupportInjection.inject(this)
        super.onAttach(context)
    }

}

class HomeFragmentViewModel() : ViewModel()

//project.gradle
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-android-extensions'

buildscript {
    repositories {
        jcenter()
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
    }
}

android {
    compileSdkVersion 27
    buildToolsVersion '26.0.2'

    defaultConfig {
        minSdkVersion 16
        targetSdkVersion 27

        applicationId "kibar.app"
        versionCode 1130
        versionName '1.1.0'
        archivesBaseName = "app-$versionName-$versionCode"
        multiDexEnabled true

        javaCompileOptions {
            annotationProcessorOptions {
                includeCompileClasspath = true
            }
        }
    }

    buildTypes {
        release {
            debuggable false
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }

        debug {
            debuggable true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    packagingOptions {
        exclude 'META-INF/rxjava.properties'
    }

    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
    }
}

kapt {
    generateStubs = true
}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'com.android.support:multidex:1.0.2'
    implementation "com.android.support:design:$android_support_version"
    implementation "com.android.support:appcompat-v7:$android_support_version"
    implementation "com.android.support:recyclerview-v7:$android_support_version"
    implementation "com.android.support:cardview-v7:$android_support_version"
    implementation "com.google.firebase:firebase-ads:$firebase_version"
    implementation "com.google.firebase:firebase-crash:$firebase_version"
    implementation "com.google.firebase:firebase-config:$firebase_version"
    implementation 'com.google.code.gson:gson:2.8.2'
    implementation 'com.jakewharton.timber:timber:4.6.0'
    implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
    implementation 'com.github.clans:fab:1.6.4'
    implementation 'com.squareup.retrofit2:retrofit:2.3.0'
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
    implementation "android.arch.persistence.room:runtime:$room_version"
    kapt "android.arch.persistence.room:compiler:$room_version"

    implementation "android.arch.lifecycle:runtime:1.0.3"
    implementation "android.arch.lifecycle:extensions:1.0.0-rc1"
    implementation "android.arch.lifecycle:reactivestreams:1.0.0-rc1"
    kapt "android.arch.lifecycle:compiler:1.0.0-rc1"

    implementation "com.google.dagger:dagger:$dagger_version"
    implementation "com.google.dagger:dagger-android:$dagger_version"
    implementation "com.google.dagger:dagger-android-support:$dagger_version"
    kapt "com.google.dagger:dagger-android-processor:$dagger_version"
    kapt "com.google.dagger:dagger-compiler:$dagger_version"
    provided 'org.glassfish:javax.annotation:10.0-b28'
}

apply plugin: 'com.google.gms.google-services'

//top.gradle
buildscript {
    ext{
        android_support_version = "27.0.0"
        kotlin_version          = "1.1.51"
        firebase_version        = "11.4.2"
        room_version            = "1.0.0-alpha9-1"
        dagger_version          = "2.12"
    }

    repositories {
        jcenter()
        maven { url "https://maven.google.com" }
        maven { url "https://jitpack.io" }
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.0'
        classpath 'com.google.gms:google-services:3.1.1'
    }
}

allprojects {
    repositories {
        jcenter()
        maven { url "https://maven.google.com" }
        maven { url "https://jitpack.io" }
    }

    gradle.projectsEvaluated {
        tasks.withType(JavaCompile) {
            options.compilerArgs << "-Xmaxerrs" << "1000"
        }
    }
}

关于如何解决这个问题的任何想法?

2 个答案:

答案 0 :(得分:1)

与错误状态一样

kibar.app.ui.fragment.HomeFragmentViewModel cannot be provided without an @Inject constructor or from an @Provides-annotated method.

你需要以某种方式提供HomeFragmentViewModel。您可以在@Module内或使用可注射构造函数

进行此操作
class HomeFragmentViewModel @Inject constructor()

答案 1 :(得分:1)

您的inject没有Provides带注释的构造函数或Module带注释的方法,例如HomeFragmentViewModel。所以你得到这个错误。

class HomeFragmentViewModel @Inject constructor(): ViewModel()

我认为这对你有帮助。