【发布时间】:2021-01-16 19:53:38
【问题描述】:
我是 Android 中 Dagger 2 的新手。我无法理解如何使用动态值注入 ViewModel。到目前为止,我已经使用带有预定义存储库依赖项的 dagger 多重绑定成功地注入了 ViewModel。这是我的代码。
应用组件
@Singleton
@Component(modules = [AppModule::class, SubComponentsModule::class, ViewModelFactoryModule::class])
interface ApplicationComponent {
@Component.Factory
interface Factory {
fun create(@BindsInstance applicationContext: Context): ApplicationComponent
}
fun activityComponent(): ActivitySubComponent.Factory
fun fragmentComponent(): FragmentSubComponent.Factory
}
片段模块
@Module
abstract class FragmentModule {
@Binds
@IntoMap
@ViewModelKey(WeatherViewModel::class)
abstract fun bindWeatherView(weatherViewModel: WeatherViewModel) : ViewModel
}
ViewModelFactoryModule
@Module
class ViewModelFactoryModule {
@Provides
@Singleton
fun viewModelFactory(providerMap: Map<Class<out ViewModel>, Provider<ViewModel>>): ViewModelProvider.Factory {
return ViewModelFactory(providerMap)
}
}
应用类
class ThisApplication: Application(),InjectorProvider {
override fun onCreate() {
super.onCreate()
Stetho.initializeWithDefaults(this)
}
override val component by lazy {
DaggerApplicationComponent.factory().create(applicationContext)
}
}
我正在使用InjectorProvider 接口来获取片段和活动,而不必每次都进行投射。
InjectorProvider
interface InjectorProvider {
val component: ApplicationComponent
}
val Activity.injector get() = (application as InjectorProvider).component
val Fragment.injector get() = (requireActivity().application as InjectorProvider).component
这是我用来测试ViewModel注入的简单ViewModel。
WeatherViewModel
class WeatherViewModel @Inject constructor(val repository: WeatherRepository): ViewModel() {
fun printMessage(){
Log.d("WeatherViewModel","ViewModel binding is working")
repository.printMessage()
}
}
最后,我将这个视图模型注入到一个片段中,如下所示。
天气片段
class WeatherFragment : Fragment() {
@Inject
lateinit var viewModelFactory: ViewModelFactory
override fun onAttach(context: Context) {
injector.fragmentComponent().create().injectWeatherFragment(this)
super.onAttach(context)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val mainActivityViewModel =
ViewModelProvider(this,viewModelFactory)[WeatherViewModel::class.java]
mainActivityViewModel.printMessage()
}
}
这部分工作正常。 printMessage() 内的日志消息被打印出来。我在匕首问题讨论中看到使用AssistedInject 是处理这种情况的最佳方法。我通过添加一个简单的 int 值作为参数更改了我的 ViewModle。
编辑的 WeatherViewModel
class WeatherViewModel @AssistedInject constructor(val repository: WeatherRepository,
@Assisted val id: Int): ViewModel() {
@AssistedInject.Factory
interface Factory{ fun create(id: Int) : WeatherViewModel }
fun printMessage(){
Log.d("WeatherViewModel","ViewModel binding is working")
repository.printMessage()
}
}
编辑的应用程序组件
@Singleton
@Component(modules = [AppModule::class, SubComponentsModule::class, ViewModelFactoryModule::class, AssistedInjectModule::class])
interface ApplicationComponent {
@Component.Factory
interface Factory {
fun create(@BindsInstance applicationContext: Context): ApplicationComponent
}
fun activityComponent(): ActivitySubComponent.Factory
fun fragmentComponent(): FragmentSubComponent.Factory
}
@AssistedModule
@Module(includes = [AssistedInject_AssistedInjectModule::class])
interface AssistedInjectModule
从现在开始,我不明白如何将ViewModel 注入到带有存储库和动态“id”值的片段中。如果我通过调用 create 方法 (val mainActivityViewModel = factory.create(5)) 将WeatherViewModel.Factory 注入到片段中,它将无法满足ViewModel 中的存储库依赖关系。如何将这两种解决方案结合起来,以实现具有动态值的预定义存储库依赖关系?或者有没有其他更好的方法来解决这个问题?
【问题讨论】:
标签: android dagger-2 android-viewmodel