2017-11-02 5 views
0

私は自分のプロジェクトでarch androidライブラリから新しいViewModelを使用しようとしています。Android Kotlin dagger 2 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([email protected]); 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" 
     } 
    } 
} 

この問題を解決する方法上の任意のアイデア?

あなたが何とか HomeFragmentViewModelを提供する必要がエラー状態と同様に
+0

'public abstract interface'? – Blackbelt

+0

はい私はgradleコンソールで見ると驚いた:public abstract interface AppComponent ...理由は分かりません – kibar

+0

'public'は_Kotlin_から来ています。 'abstract'は' interface'に暗示されています。 – tynn

答えて

1

であなたは、そのようなあなたのためのHomeFragmentViewModelModuleとしてinject注釈付きのコンストラクタまたはProvidesアノテーション付きメソッドを持っていません。だからこのエラーが発生します。

class HomeFragmentViewModel @Inject constructor(): ViewModel() 

これはあなたに役立つと思います。

+0

このエラーを見た前に、私はDaggerがHomeFragmentViewModelオブジェクトを必要としていると考えて、この行を 'ViewModelModule'に追加します:' @Provides fun provideViewModel()= HomeFragmentViewModel( ) 'しかし、私はこのエラーを受け取りました:' @Moduleは非static @Providesメソッドと抽象@Bindsまたは@Multibinds宣言の両方を含むことができません 'なぜ私は' HomeFragmentViewModel'オブジェクトを提供できませんか? – kibar

1

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

。これは、あなたが@Module以内に行うことができますまたは注射コンストラクタ

class HomeFragmentViewModel @Inject constructor() 
関連する問題