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

ViewModel cannot be provided without an @Inject constructor or an @Provides-annotated

问题已编辑

我正在将 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

@模块 public 抽象 class 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>
)

为什么我必须将 @Inject constructor 附加到每个 ViewModel 并请解释一下为什么我们需要 @Binds @IntoMap 和 ViewModel

当您使用 dagger android 时,您应该将您的活动和片段作为 DaggerActivity 的扩展(以及 DaggerFragment 的片段)。

class MainActivity : DaggerActivity() {

    @Inject
    lateinit var viewModel: MainViewModel
}

接下来你应该准备注入的基础设施:

  1. 为每个 activity:

    创建注入器
    // 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. 创建模块以提供视图模型(可以多为一activity)和工厂

    @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