[英]How to use AssistedInject to pass dynamic value as a parameter to ViewModel when using Dagger2 in Android
I am new to Dagger 2 in android.我是 android 中 Dagger 2 的新手。 I am having trouble understanding how to inject ViewModel
with dynamic value.我无法理解如何为ViewModel
注入动态值。 So Far I have successfully injected ViewModel using dagger multi binding with pre-defined repository dependency.到目前为止,我已经使用带有预定义存储库依赖项的 dagger 多重绑定成功地注入了 ViewModel。 Here's my code.这是我的代码。
ApplicationComponent应用组件
@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
}
FragmentModule片段模块
@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)
}
}
Application class应用 class
class ThisApplication: Application(),InjectorProvider {
override fun onCreate() {
super.onCreate()
Stetho.initializeWithDefaults(this)
}
override val component by lazy {
DaggerApplicationComponent.factory().create(applicationContext)
}
}
I'm using InjectorProvider
interface to get dagger to fragments and activity without having to cast every time.我正在使用InjectorProvider
接口来获得碎片和活动的匕首,而不必每次都进行强制转换。
InjectorProvider注射器提供者
interface InjectorProvider {
val component: ApplicationComponent
}
val Activity.injector get() = (application as InjectorProvider).component
val Fragment.injector get() = (requireActivity().application as InjectorProvider).component
This is the simple ViewModel
I used for testing ViewModel
injection.这是我用于测试ViewModel
注入的简单ViewModel
。
WeatherViewModel天气视图模型
class WeatherViewModel @Inject constructor(val repository: WeatherRepository): ViewModel() {
fun printMessage(){
Log.d("WeatherViewModel","ViewModel binding is working")
repository.printMessage()
}
}
Finally, I Injected this view model into a fragment like below.最后,我将此视图 model 注入到如下片段中。
WeatherFragment天气片段
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()
}
}
This part is working fine.这部分工作正常。 The Log message inside printMessage()
getting printed. printMessage()
中的日志消息被打印出来。 I saw in the dagger issue discussion that using AssistedInject is the best approach to handle this kind of scenario.我在匕首问题讨论中看到,使用AssistedInject是处理这种情况的最佳方法。 I changed my ViewModle
by adding a simple int value as a parameter.我通过添加一个简单的 int 值作为参数来更改我的ViewModle
。
Edited WeatherViewModel编辑了 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()
}
}
Edited ApplicationComponent编辑的应用程序组件
@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
From this point onwards I don't understand how to inject ViewModel
into fragment with repository plus dynamic "id" value.从这一点开始,我不明白如何将ViewModel
注入到带有存储库和动态“id”值的片段中。 If I inject WeatherViewModel.Factory
into the fragment by calling the create method ( val mainActivityViewModel = factory.create(5)
) it won't fulfill the repository dependency in ViewModel
.如果我通过调用 create 方法( val mainActivityViewModel = factory.create(5)
)将WeatherViewModel.Factory
注入片段,它将无法满足ViewModel
中的存储库依赖关系。 How to combine these two solutions to have pre-defined repository dependency with dynamic value?如何将这两种解决方案结合起来,以实现具有动态值的预定义存储库依赖关系? OR is there any other better way of approaching this?或者有没有其他更好的方法来解决这个问题?
Not quite sure why your setup wont fulfill repository
dependency by using create()
method of factory.不太清楚为什么您的设置无法通过使用工厂的create()
方法来满足repository
依赖关系。 The repository
dependency will be provided by Dagger's Acyclic Dependency Graph
. repository
依赖将由Dagger's Acyclic Dependency Graph
提供。
For example, below I'm saying to Dagger
that I am responsible for providing SavedStateHandle
and the NavigationDispatcher
so don't even bother looking these up in your acyclic dependency graph
.例如,下面我对Dagger
说,我负责提供SavedStateHandle
和NavigationDispatcher
,所以甚至不用费心在你的acyclic dependency graph
中查找它们。
class ProfileViewModel @AssistedInject constructor(
@Assisted val handle: SavedStateHandle,
@Assisted val navigationDispatcher: NavigationDispatcher,
private val eventTracker: EventTracker,
private val getUserUseCase: GetUserUseCase,
private val logOutUseCase: LogOutUseCase
) : ViewModel(), ProfileHandler {
@AssistedInject.Factory
interface Factory {
fun create(
handle: SavedStateHandle,
navigationDispatcher: NavigationDispatcher
): ProfileViewModel
}
In Fragment
side, all I have to provide in the create
method will be the dependencies
i marked with @Assisted
to fulfil my side of promise.在Fragment
方面,我必须在create
方法中提供的所有dependencies
项都是我用@Assisted
标记的,以实现我的 promise 方面。
class ProfileFragment : Fragment() {
private val navigationDispatcher by getActivityViewModel {
getBaseComponent().navigationDispatcher
}
private val eventTracker by lazy {
getProfileComponent().eventTracker
}
private val viewModel by getViewModel { savedStateHandle ->
getProfileComponent().profileViewModelFactory.create(savedStateHandle, navigationDispatcher)
}
getViewModel
is simply an extension
function as follows: getViewModel
只是一个extension
function 如下:
inline fun <reified T : ViewModel> Fragment.getViewModel(crossinline provider: (handle: SavedStateHandle) -> T) =
viewModels<T> {
object : AbstractSavedStateViewModelFactory(this, arguments) {
override fun <T : ViewModel?> create(
key: String,
modelClass: Class<T>,
handle: SavedStateHandle
) = provider(handle) as T
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.