代码之家  ›  专栏  ›  技术社区  ›  Zar E Ahmer

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

  •  0
  • Zar E Ahmer  · 技术社区  · 5 年前

    我正在注射 ViewModelProvider.Factory BaseActivity 如下

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

    class MainViewModel @Inject constructor( private val alertStore: AlertStore)
        : BaseViewModel(){
    
        fun showDialog(){
            viewModelScope.launch {
                delay(4000)
    
                alertStore.showToast("Alert after 4 seconds.")
            }
        }
    }
    

    为什么在我当前的实现中需要这个@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()
    }
    

    class App : DaggerApplication() {
    
    override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
        return DaggerAppComponent.builder().addContext(this).build()
        }
    }
    

    AppComponent.kt

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

    AppModule.kt

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

    @Module
    abstract class ActivityBuilder {
    
        //@Scope("")
        @ContributesAndroidInjector ///(modules = {MainModelFactory.class})
        public abstract MainActivity bindMainActivity();
    }
    

    @模块

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

    }

    ViewModelKey.kt

    @MapKey
    @Retention(AnnotationRetention.SOURCE)
    annotation class ViewModelKey(
        val value: KClass<out ViewModel>
    )
    

    为什么我必须附加 @注入构造函数 视图模型 请解释一下我们为什么需要

    0 回复  |  直到 5 年前
        1
  •  1
  •   Sergei Bubenshchikov    5 年前

    当你使用 匕首机器人 DaggerActivity (及 DaggerFragment 对于碎片)。

    class MainActivity : DaggerActivity() {
    
        @Inject
        lateinit var viewModel: MainViewModel
    }
    

    1. // All your injectors can be defined in this module
      @Module(includes = [AndroidInjectionModule::class])
      interface AppInjectorModule {
      
          @ContributesAndroidInjector(modules = [MainActivityVmModule::class, /*other dependecies*/])
          fun getMainActivityInjector(): MainActivity
      }
      
    2. @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
      }
      
    3. 将活动添加到 AppComponent 图表
      @Component(
          modules = [
              AppInjectorModule::class
          ]
      )
      @Singleton
      interface AppComponent : AndroidInjector<App>
      

    其他信息: Dagger & Android