如果没有@Inject构造函数或@Provides批注

时间:2019-11-20 12:28:40

标签: android dagger-2 android-architecture-components android-viewmodel

问题已编辑

我正在将{strong> 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)
    }
}

viewModel仅在我们如下注入时起作用。

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

}

App.kt

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

ActivityBuilder.kt

@Module
abstract class ActivityBuilder {

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

ViewModelInjector.kt

@模块 公共抽象类ViewModelInjector {

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

为什么我必须向每个 ViewModel 附加 @Inject构造子,并解释一下为什么我们需要 @Binds @IntoMap 以及ViewModel

1 个答案:

答案 0 :(得分:1)

使用 dagger android 时,应将活动和片段作为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