I have a doubt regarding Dagger 2.
I have a BaseFragment class in which i am writing AndroidSupportInjection.inject(this), and all my fragments are extending from this Fragment class. I also have a FragmentBuilder class where i mention all the Fragments using #ContributesAndroidInjector annotation where i need injection to happen.
My doubt is, if in a Fragment i don’t need any dependency still i have to mention it in my FragmentBuilder class because its extending from BaseFragment. Is it a all right to do so or this will lead to any memory leak or is this a wrong design pattern ?
Please help!!
In your situation i'll go with 2 "base" fragments, the first BaseFragment doesn't allow injection then you make a BaseInjectableFragment that inherit from the first one and you make it injectable, this looks more cleaner this way.
Related
So my question is as I am getting started with Hilt, do we need to mark all activities with #AndroidEntryPoint annotation or can we just create a BaseActivity and extend it to AppCompactActivity and mark that single class as the entry point?
Will this work? and what, if any, are the drawback of this style.
Thanks.
I'm not sure if this is a comprehensive answer, maybe it's more of a personal opinion, but I'd ask what's the goal?
Are you trying to reduce boiler plate/amount of code you need to write? Then I'm afraid it'll be the same if not more, since you'll have to go to every activity and add the inheritance part.
The downside to me is that you're now using inheritance to implement something that was avoiding it. Annotations give you the opportunity to annotate any activity without saying it's a base activity. This is often better than inheritance since not every activity is a base activity and you decouple your code more from what dagger is actually doing. I think this is more of a delegate pattern or maybe more like a decorator.
That said, to answer your question, I'm not 100% this works, but to me it has the downsides of using inheritance for something that should not be modelled by inheritance.
You cannot mark a "base class" as an AndroidEntryPoint if it is abstract, so this idea would not work anyway. As there is usually one Activity per App (recommended by google), you should not make your life harder than it is. Just annotate an Activity with #AndroidEntryPoint and you are done here.
as the document says:
Classes that Hilt injects can have other base classes that also use
injection. Those classes don't need the #AndroidEntryPoint annotation
if they're abstract.
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.
So here are the things I know from the doc
Dagger Android under the hood is creating subcomponent for each Activity annotated with ContributesAndroidInjector
You can apply custom scope to the method where ContributesAndroidInjector is annotated to
If two sibling subcomponents have the same scope, they will still have different scope instances
If an Activity is in a subcomponent, it can have its own subcomponent which can contain Fragments. Those Fragments will share the scoped instances the Activity has.
Now my question is:
How to have one Activity be a subcomponent of another activity using Dagger Android?
I want to do this because I want to achieve things like #UserScope/#SessionScope.
From this I know that I can do it with just Dagger not Dagger Android. But with Dagger Android, you can only have the Application (which is the AndroidInjector) to inject Activity. You can not have an Activity used as a holder or host of the parent subcomponent to inject another Activity.
Am I understanding it correctly?
05/14/2018 Update:
I ended up getting rid of Dagger Android. So no more ContributesAndroidInjector, just pure Dagger. And to inject Activity/Fragment, I use the way that's recommended here. It will be something like this:
class MyActivity : AppCompatActivity() {
private val factory: ViewModelProvider.Factory = Injector.myCustomScope().factory()
}
And we are trying to make sure the factory is the only thing that Activity/Fragment needs.
So far it's been great.
How to have one Activity be a subcomponent of another activity using Dagger Android?
tl;dr You can't. Dagger Android follows a strict AppComponent > ActivityComponent > FragmentComponent scheme and there is no way to add custom scopes in-between.
I suggest you have a look at the Dagger Android source code, it's really not that much. It's basicalle a HashMap for each layer where you look up the component builder and build the subcomponent. A fragment looks at its parent Activity, an Activity looks at the Application. There is no feature where you can add custom components between layers.
What you can do is create your own variant of "Dagger Android" where you can implement your own interfaces and mix/match components as you need them. But that's quite a bit of extra work. I created a #PerScreen scope that survives configuration changes as a proof of concept if you are interested to see how you could do such a thing.
You can create a custom Scope called for example #PerScreen, also you will have #PerActvity scope. The difference between these scopes is that the #PerActivity scope will maintain shared dependencies between all activities like Context, Layout Inflater, etc. And all activity specific dependencies will be scoped as #PerScreen.
#PerApplication -> #PerActivity -> #PerScreen
This could structured like that.
I have explained scopes under the hood in my blog post, you can refer to it to get better understanding of this matter.
Is there a way in Dagger2 or in Dagger2 Android Injection support to inject the member instances without specifying the class names of the fragments.
I have a modular project where
The following line is asking to provide a binder Factory for the injectable class.
#Override
public void onAttach(Context context) {
AndroidSupportInjection.inject(this);
super.onAttach(context);
}
But my intention is to provide the injecting members through different modules in the project, where the I wouldn't need to specify the class name of the Fragment at all.
Is this possible in Dagger2 injection or not?
Is there a way in Dagger2 or in Dagger2 Android Injection support to inject the member instances without specifying the class names of the fragments.
tl;dr No. You always need a component that contains a .inject(FragmentInQuestion fragment) method for every Fragment you want to inject.
Dagger uses annotation processing at compile time to resolve all of your .inject(SomeFragment fragment) methods where it looks up fields annotated with #Inject and creates code to inject them.
It needs the actual class name, since it will only generate code for the class used with its fields.
class Fragment {
// no #Inject annotated fields, part of framework!
}
class SomeFragment extens Fragment {
#Inject SomeDependency dep;
}
class OtherFragment extens Fragment {
#Inject OtherDependency dep;
}
Declaring one generic component that injects all your fragments is impossible.
.inject(Fragment fragment) would not inject any properties, since Fragment does not contain any #Inject annotated fields. So neither of the dep fields in the above sample would be provided and they both would be null.
You could create a BaseFragment that contains common objects and write an injection for it, but again, any annotated fields of its children would not be supplied.
You could try some other workarounds, but in the end it would always mean that you'd be injecting or be working with a base type. While this might be feasible in some situations, I don't think it would work on more than some special edge cases.
The Android Injection part of Dagger 2 takes this approach and creates a generic interface that your components have to implement along with a Builder to bind the type in question.
interface AndroidInjector<T> {
inject(T instance)
}
By implementing this interface AndroidInjection can then look up (and create) the correct component and inject your Fragment. For the reasons mentioned above this will always be the actual class of your Fragment, and not some base type.
So by using the Android Injection part you won't be able to use some common base class, and even without it you'd have a hard time.
If you're looking for a way to move out the call of AndroidInjection.inject(this) to somewhere else you should look at the Google Android Architecture Components sample project where they use FragmentLifecycleCallbacks to inject the fragments globally at the right time.
i have been using RoboGuice dependency injection with a Activity and a Fragment Activity. But i cannot figure out how i can use it using a fragment as we dont call setContentview in the Fargment. Can anyone show me an example of how to use this ?
Kind Regards
Here's a post that describes the solution. Main steps are:
Extend RoboFragment.
Return a root View from onCreateView().
Use #InjectView annotations the same way you do in RoboActivity.