Reputation: 65
As mentioned in the title I've got a problem with Dagger 2 injection. I have a single activity and multiple fragments. I'm trying to share activity's ViewModel with every child fragment. I based my solution on Google's Android Architecture ToDo sample. I've created ViewModelFactory as
If you jump to the link you will see that in their solution there's a separate ViewModel for every activity and fragment. They are not showing how to deal with scenarios like mine. My implementation of ActivityModule looks like:
@Module
abstract class SampleModule {
@ContributesAndroidInjector(
modules = [
ViewModelBuilder::class
]
)
internal abstract fun sampleActivity(): SampleActivity
@Binds
@IntoMap
@ViewModelKey(SampleViewModel::class)
abstract fun bindViewModel(viewModel: SampleViewModel): ViewModel
}
My activity extends DaggerAppCompatActivity
and fragment DaggerFragment
and as follows my injection of view model looks simple as
class SampleActivity : DaggerAppCompatActivity() {
@Inject
lateinit var viewModel: SampleViewModel
...
I can't find a web solution to my problem. I'm a pretty novice user of Dagger. I've tried to implement Subcomponent but still, it's not working because all the examples I have searched so far didn't use DaggerApplication
, DaggerAppCompatActivity
and my way of injection. Please suggest any solution or if a subcomponent way is right please show me how to do it if it's possible in my current architecture.
Thank you very much in advance.
Upvotes: 2
Views: 2446
Reputation: 61
I solved the problem with a slightly different approach. Since the fragments and the activity both have dagger modules. In the ActivityModule I am providing the sharedViemodel as below
@Module
class ActivityModule(private val activity: AppCompatActivity)
{
@Provides
fun provideMainSharedVieModel() : MainSharedViewModel =
ViewModelProvider(activity).get(MainSharedViewModel::class.java)
}
And in my fragment module I am again providing the same viemodel as below:
@Module
class FragmentModule(private val fragment: Fragment)
{
@Provides
fun provideMainSharedVieModel() : MainSharedViewModel =
ViewModelProvider(fragment.activity!!).get(MainSharedViewModel::class.java)
}
Since the ViewModels are stored in a map with the activity or fragments as the key, hence providing the sharedViewModel with "fragment.activity!!" in the Fragment module will not create a new instance of the viewmodel , it will just the return the already instantiated shared viewmodel to the fragment.
Upvotes: 0
Reputation: 657
@silaros88 I was facing yor same issue, share a ViewModel between multiple fragmnets in a single Activity application, and i solved playing with the ViewmModelStoreOwner
.
Steps to fix your issue.
ViewModelProvider.Factory
instead of the ViewModel
Retrieve the desire ViewModel using one of this two options:
viewModels<SharedDesireViewModel> (requireActivity()) { Injected ViewModelProvider.Factory }
ViewModelProvider(requireActivity(), Injected ViewModelProvider.Factory ).get(SharedDesireViewModel::class.java)
Examples:
Option #1:
FragmentA.kt
class FragmentA: DaggerFragment() {
@Inject
lateinit var viewModelProviderFactory: ViewModelProvider.Factory
private val mainViewModel: MainViewModel by viewModels({requireActivity()}) { viewModelProviderFactory }
......
FragmentB.kt
class FragmentB: DaggerFragment() {
@Inject
lateinit var viewModelProviderFactory: ViewModelProvider.Factory
private val mainViewModel: MainViewModel by viewModels({requireActivity()}) { viewModelProviderFactory }
......
Option #2:
FragmentA.kt
class FragmentA: DaggerFragment() {
@Inject
lateinit var viewModelProviderFactory: ViewModelProvider.Factory
private val mainViewModel: MainViewModel by lazy {
ViewModelProvider(requireActivity(), viewModelProviderFactory)
.get(MainViewModel::class.java)
}
......
FragmentB.kt
class FragmentB: DaggerFragment() {
@Inject
lateinit var viewModelProviderFactory: ViewModelProvider.Factory
private val mainViewModel: MainViewModel by lazy {
ViewModelProvider(requireActivity(), viewModelProviderFactory)
.get(MainViewModel::class.java)
}
......
Upvotes: 1