Android 如果没有@Inject构造函数或@Provides注释构造函数,则无法提供ViewModel

Android 如果没有@Inject构造函数或@Provides注释构造函数,则无法提供ViewModel,android,dagger-2,android-architecture-components,android-viewmodel,Android,Dagger 2,Android Architecture Components,Android Viewmodel,问题已编辑 我正在向BaseActivity注入ViewModelProvider.Factory,如下所示 open class BaseActivity : DaggerAppCompatActivity() { @Inject lateinit var factories: ViewModelProvider.Factory inline fun <reified T : ViewModel> getViewModel(): T {

问题已编辑

我正在向
BaseActivity
注入ViewModelProvider.Factory,如下所示

open class BaseActivity : DaggerAppCompatActivity() {

    @Inject
    lateinit var factories: ViewModelProvider.Factory

    inline fun <reified T : ViewModel> getViewModel(): T {
        return ViewModelProvider(this, factories).get(T::class.java)
    }
}
为什么在我当前的实现中需要这个@Inject构造函数

class MainActivity : BaseActivity() {

  private lateinit var viewModel: MainViewModel

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    viewModel = getViewModel()
    viewModel.showDialog()
}
}

App.kt

class App : DaggerApplication() {

override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
    return DaggerAppComponent.builder().addContext(this).build()
    }
}
@Component(
    modules = [
        AndroidInjectionModule::class,
        AppModule::class,
        ActivityBuilder::class,
        ViewModelInjector::class

    ]
)
@Singleton
interface AppComponent : AndroidInjector<App> {

    @Component.Builder
    interface Builder {

        fun addContext(@BindsInstance context: Context): Builder

        fun build(): AppComponent
    }
}
@Module
class AppModule {

    @Provides
    fun provideViewModelFactories(viewModels: Map<Class<out ViewModel>,
            @JvmSuppressWildcards Provider<ViewModel>>):
            ViewModelProvider.Factory {
        return object : ViewModelProvider.Factory {
            override fun <T : ViewModel?> create(modelClass: Class<T>): T {
                val factory = viewModels[modelClass]?.get() ?: error(
                    "No factory provided against ${modelClass.name}"
                )
                @Suppress("UNCHECKED_CAST")
                return factory as T
            }
        }
    }
}
@MapKey
@Retention(AnnotationRetention.SOURCE)
annotation class ViewModelKey(
    val value: KClass<out ViewModel>
)
ViewModelInjector.kt

class App : DaggerApplication() {

override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
    return DaggerAppComponent.builder().addContext(this).build()
    }
}
@Component(
    modules = [
        AndroidInjectionModule::class,
        AppModule::class,
        ActivityBuilder::class,
        ViewModelInjector::class

    ]
)
@Singleton
interface AppComponent : AndroidInjector<App> {

    @Component.Builder
    interface Builder {

        fun addContext(@BindsInstance context: Context): Builder

        fun build(): AppComponent
    }
}
@Module
class AppModule {

    @Provides
    fun provideViewModelFactories(viewModels: Map<Class<out ViewModel>,
            @JvmSuppressWildcards Provider<ViewModel>>):
            ViewModelProvider.Factory {
        return object : ViewModelProvider.Factory {
            override fun <T : ViewModel?> create(modelClass: Class<T>): T {
                val factory = viewModels[modelClass]?.get() ?: error(
                    "No factory provided against ${modelClass.name}"
                )
                @Suppress("UNCHECKED_CAST")
                return factory as T
            }
        }
    }
}
@MapKey
@Retention(AnnotationRetention.SOURCE)
annotation class ViewModelKey(
    val value: KClass<out ViewModel>
)
@模块 公共抽象类ViewModelInjector{

@Binds
@IntoMap
@ViewModelKey(MainViewModel.class)
public abstract ViewModel providesMainViewModel(MainViewModel model);
}

ViewModelKey.kt

class App : DaggerApplication() {

override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
    return DaggerAppComponent.builder().addContext(this).build()
    }
}
@Component(
    modules = [
        AndroidInjectionModule::class,
        AppModule::class,
        ActivityBuilder::class,
        ViewModelInjector::class

    ]
)
@Singleton
interface AppComponent : AndroidInjector<App> {

    @Component.Builder
    interface Builder {

        fun addContext(@BindsInstance context: Context): Builder

        fun build(): AppComponent
    }
}
@Module
class AppModule {

    @Provides
    fun provideViewModelFactories(viewModels: Map<Class<out ViewModel>,
            @JvmSuppressWildcards Provider<ViewModel>>):
            ViewModelProvider.Factory {
        return object : ViewModelProvider.Factory {
            override fun <T : ViewModel?> create(modelClass: Class<T>): T {
                val factory = viewModels[modelClass]?.get() ?: error(
                    "No factory provided against ${modelClass.name}"
                )
                @Suppress("UNCHECKED_CAST")
                return factory as T
            }
        }
    }
}
@MapKey
@Retention(AnnotationRetention.SOURCE)
annotation class ViewModelKey(
    val value: KClass<out ViewModel>
)
@MapKey
@保留(AnnotationRetention.SOURCE)
注释类ViewModelKey(
val值:KClass
)
为什么我必须将@injectconstructor附加到每个ViewModel中,并请解释一下为什么我们需要@Binds@IntoMap,当你使用dagger android时,你应该将你的活动和片段作为
DaggerActivity
(对于碎片,
DaggerFragment

接下来,您应该为注入准备基础架构:

  • 为您的每项活动创建注射器:

    // All your injectors can be defined in this module
    @Module(includes = [AndroidInjectionModule::class])
    interface AppInjectorModule {
    
        @ContributesAndroidInjector(modules = [MainActivityVmModule::class, /*other dependecies*/])
        fun getMainActivityInjector(): MainActivity
    }
    
  • 创建模块以提供视图模型(一个活动可以有多个)和工厂模型

    @Module(includes = [VmFactoryModule::class])
    abstract class MainActivityVmModule {
    
        // bind implementation of ViewModel into map for ViewModelFactory
        @Binds
        @IntoMap
        @ClassKey(MainViewModelImpl::class)
        abstract fun bindMainVm(impl: MainViewModelImpl): ViewModel
    
        @Module
        companion object {
            @Provides
            @JvmStatic
            fun getMainVm(activity: MainActivity, factory: ViewModelProvider.Factory): MainViewModel {
                // create MainViewModelImpl in scope of MainActivity and inject dependecies by ViewModelFactory
                return ViewModelProviders.of(activity, factory)[MainViewModelImpl::class.java]
            }
        }
    }
    
    工厂可提供不同的模块,以避免重复

    @Module
    interface VmFactoryModule {
    
        @Binds
        // bind your implementation of factory
        fun bindVmFactory(impl: ViewModelFactory): ViewModelProvider.Factory
    }
    
  • 将活动添加到
    AppComponent
    图形
    @Component(
        modules = [
            AppInjectorModule::class
        ]
    )
    @Singleton
    interface AppComponent : AndroidInjector<App>
    
    @组件(
    模块=[
    AppInjectorModule::类
    ]
    )
    @独生子女
    
    接口AppComponent:AndroidJector

    请解释MainActivityVmModule以及@Binds、IntoMap和ClassKey。为什么我们不在注入活动或片段中使用,而在为ViewModel添加注释。请看我更新的问题,它现在运行良好。但我的概念不正确clear@XarEAhmer使用
    @Binds
    接近匕首时r创建依赖项(Vm)自动,但您应该在构造函数上设置注释
    @Inject
    。您应该明确地说dagger应该使用哪个构造函数来创建Vm和注入依赖项。您还可以通过模块的方法使用
    @手动创建依赖项提供注释并通过setter设置依赖项(不推荐):
    @提供有趣的getVm(活动:活动,依赖项:VmDependency):ViewModel=ViewModelProviders.of(活动)[MainViewModelImpl::class.java]。应用{this.dependency=dependency}