Dagger-Hilt : Why we must annotate Activities which has no injection - android

Why we must to annotate activities which contains fragments on it ?
Activity has no #Inject but fragments need some dependencies .
I annotate fragments as #AndroidEntryPoint but crash until set this on parent activity.

You can't start a Fragment without an Activity. You have to annotate your Activity with #AndroidEntryPoint because your fragment is a HiltComponent now. When you don't annotate your Activity with #AndroidEntryPoint Hilt would not create a component for this activity and thus could not start the fragment because it didn't create the ActivtyComponent yet.
Hilt activities need to be attached to Hilt applications. Hilt
fragments must be attached to Hilt activities.
See here: https://dagger.dev/hilt/migration-guide (2. Migrate Activities and Fragments)

Related

Android Dagger - How to Inject from other module

I've multiple modules in my app, each one of them have his own Module for UI Injection.
Now, i want to have "feed" fragment that have a some pieces from other modules.
So i trying doing it using FragmentContainerView.
I want to Inject the fragment that defined on other module. I'm trying to "include" my other fragment, so i can navigate into this fragment, but if i'm try to inject it, i'm getting this following error:
error: [Dagger/MissingBinding] DotsFragment cannot be provided without an #Inject constructor or an #Provides-annotated method. This type supports members injection but cannot be implicitly provided.
Any idea how can i do it?
HomeModule:
#Module(
includes = [
DotsModule::class
]
)
abstract class HomeModule {
}
DotsModule:
#Module
abstract class DotsModule {
#FragmentScoped
#ContributesAndroidInjector
abstract fun contributeDotsFragment(): DotsFragment
}
HomeFragment:
#Inject
lateinit var dotsFragment: DotsFragment
Just push the Fragment into the container as described in the docs, and don't worry about the injection. You don't even need the explicit inclusion of DotsModule from HomeModule, though you may choose to keep it, especially if HomeModule is in a different Activity. DotsFragment will inject itself in onAttach.
Unlike most classes that use Dagger injection, Fragments can't be injected in their constructors: Android will only call the zero-arg or one-arg Fragment() constructor, so there isn't room for other constructor parameters. When you see your abstract fun contributeDotsFragment() function with #ContributesAndroidInjector, it is not the case that DotsFragment is available on your graph to be constructed or provided. Instead, Dagger does some magic1 that allows the Fragment to have its #Inject-labeled fields populated2 once you call AndroidSupportInjection.inject(this) in onAttach, which might happen in DaggerFragment if you inherit from that. Your Fragment has to assume that anything marked #Inject is null until the Fragment is attached.
Consequently, if you need an instance of DotsFragment, you can just call DotsFragment() or delegate to your FragmentManager's FragmentFactory (which will likely just call DotsFragment()). You can also use overloads to FragmentTransaction.replace(...) that take a Class<Fragment> rather than a Fragment instance.
The Fragment will inject itself later in onAttach, as it would if Android itself called the constructor. If you interact with the Fragment before that, be careful, as its #Inject-annotated fields will not be populated yet. If you need to interact with the Fragment in ways that use Dagger-provided instances, it may be best to create a Bundle that the Fragment can use to initialize itself in onCreate.
1: Behind the scenes, dagger.android creates a code-generated subcomponent instance, probably called DotsModule_BindDotsFragment.DotsFragmentSubcomponent, and registers that subcomponent as an AndroidInjector.Factory<DotsFragment> in a Map. The generated subcomponent receives all the modules you set on the #ContributesAndroidInjector annotation as well as all the scope annotations you set on the abstract fun. In onAttach (yours or DaggerFragment's), the call to AndroidSupportInjection.inject(this) reads from that Map, finds the Injector/Subcomponent, creates an instance, and uses that to inject the Fragment with its own set of #FragmentScope instances.
2 The #Inject-annotated methods will be called too. That's method injection, compared to field injection; the general term is members injection for all of the post-constructor initialization Dagger can do.

Android Hilt scope for fragment ViewModel

In the doc, you can see this graph:
So there is this "ActivityRetainedScope" for activity ViewModel, but what about fragment ViewModel? What is the right scope to be used in this case? And the same question for the component, I don't see a component for the fragment ViewModel?

Hilt Fragments must be attached to an #AndroidEntryPoint Activity. Found: class

Is it mandatory to add #AndroidEntryPoint annotation on all dependent classes like fragment dependent upon activity. Is there any alternative solution for overcome this exception?
Just add #AndroidEntryPoint to your parent Activity class:
And yes, it's a mandatory process if you want to use Hilt. You could use Dagger to get away with this.

Android mvvm should I use 2 ViewModels, 1 ViewModel in two views, or 1 in Parent activity?

Given the case : ProfileActivity and EditProfileActivity both extend from a BaseActivity, should each activity have their own viewmodel (ProfileViewModel and EditProfileViewModel), use the same viewmodel in the two activities or inherit the model from the parent but obverse it in each activity?
Thanks
It depends on the scope of your ViewModels. If you want your activities to communicate with each other, then you can create a BaseViewModel scoped to your BaseActivity and use that to do IPC among ProfileActivity and EditProfileActivity, given that they expend BaseActivity.
You can also create three viewModels, one for each. Use the BaseViewModel for IPC and the ProfileViewModel and editProfileViewModel for delegation, where the activities will be light themselves and will delegate everything down to their viewModels. This can be achieved through the combination of LiveData observers and DataBinding.

Fragment with viewmodel bound to an activity being used in multiple Activities

Currently I have a fragment class with a viewmodel being used in multiple activities. The viewmodel(viewModelOne) was added to be used in Activity1 but when Activity2 uses the fragment there is a runtime exception since the fragment's viewmodel is scoped to be used in the activity(eg. ViewModelProviders.of(getActivity()) and Activity2 doesn't instantiate viewModelOne. The easy solution is to create the viewModelOne instance in the Activity2 class but i am not a fan of this solution since viewModelOne is not relevant for this activity class. Any other solutions or recommendations?

Categories

Resources