如果没有 @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
}
接下来你应该准备注入的基础设施:
为每个 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
}
创建模块以提供视图模型(可以多为一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
}
- 将活动注入器添加到
AppComponent
图中
@Component(
modules = [
AppInjectorModule::class
]
)
@Singleton
interface AppComponent : AndroidInjector<App>
附加信息:Dagger & Android
问题已编辑
我正在将 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
}
接下来你应该准备注入的基础设施:
为每个 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 }
创建模块以提供视图模型(可以多为一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 }
- 将活动注入器添加到
AppComponent
图中@Component( modules = [ AppInjectorModule::class ] ) @Singleton interface AppComponent : AndroidInjector<App>
附加信息:Dagger & Android