我试图在我的项目中使用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"
}
}
}
关于如何解决这个问题的任何想法?
答案 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()
我认为这对你有帮助。