问题
In Dagger, how can I add a model to Module? For example I added the presenter in the following way:
@Module
class AboutModule(val appContext: Context) {
@FragmentScope
@Provides
fun providePresenter(): AboutListContract.Presenter {
return AboutListPresenter(appContext = appContext)
}
}
Now i want want to add my View model, also with appContext.
class AboutViewModel(val appContext: Context): ViewModel() {
UPDATE: Can i add my view model smth like this?
@Module
class AboutModule(val appContext: Context) {
@FragmentScope
@Provides
fun provideModel(model: AboutViewModel): ViewModel {
return AboutViewModel(appContext = appContext)
}
}
回答1:
I solved my problem with next solution:
@Module
class AboutModule(val appContext: Context) {
@FragmentScope
@Provides
fun provideFactory(): AboutViewModelFactory {
return AboutViewModelFactory(appContext)
}
}
And in fragment write smth like this: class AboutFragment : BaseFragment(), OnItemClickListener {
lateinit var viewModel: AboutViewModel
@Inject lateinit var viewModelFactory: AboutViewModelFactory
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
injectDependencies()
viewModel = ViewModelProviders
.of(this, viewModelFactory)
.get(AboutViewModel::class.java)
}
private fun injectDependencies() {
activity?.let {
DaggerAboutComponent.builder().aboutModule(AboutModule(it)).build().inject(this)
}
}
Nice advise: https://stackoverflow.com/a/60884492/6387618
回答2:
To retrieve the ViewModel from the component without Map Multibinding, you can do:
@Singleton
@Component(modules=[...])
interface SingletonComponent {
val aboutListViewModel: Provider<AboutListViewModel>
}
Which works when you can use @Inject constructor
:
// unscoped
class AboutListViewModel @Inject constructor(): ViewModel() {
}
Because now you can do:
class AboutListFragment: Fragment(R.layout.about_list_fragment) {
private val viewModel by viewModels<AboutListViewModel>() {
object: ViewModelProvider.Factory {
override fun create(clazz: Class<ViewModel>) {
return (requireActivity().application as MyApplication).component.aboutListViewModel.get()
}
}
}
}
Which might seem tacky, but you can hide all of that in an extension function
fun <T: ViewModel> Fragment.fragmentViewModels(viewModelCreator: SingletonComponent.() -> T) = viewModels<T> {
object: ViewModelProvider.Factory {
override fun create(clazz: Class<ViewModel>) {
val component = requireActivity().application as MyApplication).component
return viewModelCreator(component)
}
}
}
Because now you can do
class AboutListFragment: Fragment(R.layout.about_list_fragment) {
private val viewModel by fragmentViewModels<AboutListViewModel> { component ->
component.aboutListViewModel().get()
}
}
And this would work even without map multibinding. If you need a SavedStateHandle
, you'd need AssistedInject, but if you don't want that, it'll be easier when Dagger-Hilt is stable (then it'll be as simple as @ViewModelInject
and @Assisted
).
回答3:
ViewModels are injected using Dagger Multibindings
refer to this medium article: https://medium.com/chili-labs/android-viewmodel-injection-with-dagger-f0061d3402ff
context
can be injected by providing in the AppModule class.
来源:https://stackoverflow.com/questions/60884402/how-i-can-add-view-model-in-module