Injecting presenters with MVP/Dagger 2 - android

I've been learning about DI and Dagger 2 recently, and I feel like I'm ending up with more boilerplate than what I started with. My setup includes
AppComponent -- provides Application, Resources and other networking-related stuff. #Singleton Scoped.
Feature1Component, Feature2Component.... -- provide repositories used across screens. #Feature scoped, subcomponents of AppComponent. Has 'plus' methods for screen components.
Screen1Component, Screen2Component... -- this is where the feeling of boilerplate comes in - each screen component just has an 'inject' method for the Fragment/Activity that is being used to depict the screen. Subcomponent of FeatureXComponent. Each corresponding module ends up looking just like so:
#Module
public class Screen1Module
{
private final Screen1Contract.View view;
public Screen1Module(Screen1Contract.View view)
{
this.view = view;
}
#Provides
public Screen1Contract.View provideView()
{
return view;
}
}
So as a result, for each screen, I end up writing a Component and Module since I can only call the following:
((MyApplication) getActivity().getApplication())
.getFeature1Component()
.newScreen1Component(new Screen1Module(this))
.inject(this);
when I'm initializing my view (Activity or Fragment), for the benefit of injecting just the presenter.
Is there a way to do this which does not involve as much boilerplate? I was hoping to inject screens at the "Feature" level, but I guess that isn't really possible since screens have a shorter life cycle than features.

This is why dagger-android is born since dagger 2.10. It simplifies injection of Android core types.
#ContributesAndroidInjector replaces subcomponents. DaggerActivity and others get rid of getComponent()....inject(this)
its official doc
and a pretty good article I found recently

Related

How do I use AndroidInjection class in custom views or other android classes?

My issue with the Android-specific pattern is, if you use their AndroidInjection class, there is no way to members inject other objects besides Activities/Fragments/custom views/adapters, except with the Application Component. This is because you cannot get a reference the the Subcomponent (AndroidInjector) used to inject Activities/Fragments.
This makes injecting Dialogs (if you use DialogFragments).
The AndroidInjection class seems to support just the core Android types.
What follows is not an answer to your question, but an explanation why you shouldn't be asking this question at all.
You should avoid injections into custom Views in general. The reasons for this are listed in this article.
Advantages of using Method Injection in this case [injection into custom Views] are:
Dependencies will need to be propagated from top level component (Activity or Fragment)
Method Injection does not open door to Single Responsibility Principle violation
No dependency on the framework
Better performance
The first advantage might come as a surprise because propagation from
top level component is harder than adding annotation to fields, and
involves more boilerplate code. This is surely a bad thing, right?.
Not in this case. In fact, there are two good aspects associated with
such a propagation of dependencies. First of all, the dependencies
will be visible at the top level component. Therefore, just by looking
at e.g. Fragment‘s fields, the reader of the code will immediately
understand that this Fragment shows images. Such optimizations for
readability makes the system more easily maintainable in the long
term. Secondly, there are not many use cases in which sub-classes of
View need additional dependencies. The fact that you need to actually
work in order to provide these dependencies will give you a bit of
time to think about whether providing them is a good design decision
to start with.
The second advantage is related to collaborative construction. You
might be very experienced software engineer yourself, but you’ll
probably have also less experienced teammates. Or it is possible that
you’ll leave the project one day, and the guy who will take over will
not be as good as you. By injecting one single dependency using a
framework, you basically open a door for other injections. Imagine
that some data from SharedPreferences becomes required in custom View
in order to e.g. fix a bug. One of the less experienced developers
might decide that it is a good approach to inject SharedPreferences
into custom View directly. Doing this violates Single Responsibility
Principle, but that developer might not even be aware of such a
concept. Therefore, in the long term, such injection “backdoors” can
reduce design quality and lead to long debug sessions.
The third advantage of using Method Injection with custom Views is
that you don’t couple the View to dependency injection framework. Just
imagine that few years from now you (or some other poor guy) need to
replace the framework. The fact that you’ll probably have tens of
Activities and Fragments to start with will make your life miserable.
If you’ll have additional tens or hundreds of custom Views to handle,
then it might bring you into suicidal mood.
The last (but not least) advantage is performance. One screen can
contain one Activity, several Fragments and tens of custom Views.
Bootstrapping this number of classes using dependency injection
framework might degrade application’s performance. It is especially
true for reflection based frameworks, but even Dagger carries some
performance cost.
In addition, I advice to avoid the new injection method that involves AndroidInjection class. It is discussed in this video tutorial.
First, you should think over Vasily's answer.
But let's think for a moment how we did this before Dagger Android?
We built a subcomponent from the component that was taken from the Application class. Later, we could use this subcomponent in order to inject fields, for example, of a custom view.
So, we'll try to do the exact same thing now.
Suppose, our aim is to inject MyAdapter class into a MyButton:
public class MyButton extends AppCompatButton {
#Inject MyAdapter adapter;
public MyButton(Context context) {
super(context);
...
}
}
And let's make the adapter have a dependency on the activity Context, not application Context:
public class MyAdapter {
#Inject
public MyAdapter(#Named("activity") Context context) {
}
}
Let's start with the custom Application class.
MyApplication.java
public class MyApplication extends DaggerApplication {
#Inject
DispatchingAndroidInjector<Activity> dispatchingActivityInjector;
public static MySubcomponent mySubcomponent;
#Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
return DaggerAppComponent.builder()
.create(this);
}
}
AppComponent.java:
#Component(modules = {AndroidSupportInjectionModule.class, ActivityBindingModule.class, AppModule.class})
#Singleton
public interface AppComponent extends AndroidInjector<MyApplication> {
#Component.Builder
abstract class Builder extends AndroidInjector.Builder<MyApplication> {
}
}
AppModule.java
#Module
abstract class AppModule {
#Binds
#Singleton
#Named("app")
abstract Context providesContext(Application application);
}
ActivityBindingModule.java
#Module(subcomponents = MySubcomponent.class)
public abstract class ActivityBindingModule {
#Binds
#IntoMap
#ActivityKey(MainActivity.class)
abstract AndroidInjector.Factory<? extends Activity>
bindMainActivityInjectorFactory(MySubcomponent.Builder builder);
}
AndroidSupportInjectionModule.java is shipping with dagger itself. If you do not use classes from support package (i.e. android.support.v4.app.Fragment instead of android.app.Fragment), then use AndroidInjectionModule.java.
MySubcomponent.java
#ActivityScope
#Subcomponent(modules = {SubcomponentModule.class/*, other modules here, if needed */})
public interface MySubcomponent extends AndroidInjector<MainActivity> {
void inject(MyButton button);
#Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<MainActivity> {
public abstract MySubcomponent build();
}
}
SubcomponentModule.java
#Module
abstract class SubcomponentModule {
#Binds
#ActivityScope
#Named("activity")
abstract Context toContext(MainActivity activity);
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Inject
MySubcomponent subcomponent;
#Override
protected void onCreate(Bundle savedInstanceState) {
// Will inject `subcomponent` field
AndroidInjection.inject(this);
// Saving this component in a static field
// Hereafter you are taking responsibility of mySubcomponent lifetime
MyApplication.mySubcomponent = subcomponent;
super.onCreate(savedInstanceState);
setContentView(new MyButton(this));
}
}
Having all of these, now here's how MyButton will look like:
public class MyButton extends AppCompatButton {
#Inject MyAdapter adapter;
public MyButton(Context context) {
super(context);
MyApplication.mySubcomponent.inject(this);
}
}
I admit that this looks hacky and certainly not an approach to stick to. I'm happy to see a better approach.
This is because you cannot get a reference the the Subcomponent (AndroidInjector) used to inject Activities/Fragments.
You can always just inject the component itself. Just add a field for the component to your Activity / Fragment and let Dagger inject it along with the rest.
// will be injected
#Inject MainActivitySubcomponent component;
The issue of whether the dagger-android classes like AndroidInjector should support injection inside Views or not has been discussed in the following Github issue:
https://github.com/google/dagger/issues/720
Quoting from one of the library authors:
There is both a philosophical point and logistical/implementation point to be made here.
First, it's not fully clear to us that injecting views is the right thing to do. View objects are meant to draw, and not much else. The controller (in a traditional MVC pattern) is the one which can coordinate and pass around the appropriate data to a view. Injecting a view blurs the lines between fragments and views (perhaps a child fragment is really the appropriate construct instead?)
From the implementation perspective, there is also a problem in that there isn't a canonical way to retrieve the View's parent Fragments (if any), or Activity to retrieve a parent component. There have been hacks suggested to build in that relationship, but so far we haven't seen anything that seems to suggest that we could do this correctly. We could just call View.getContext().getApplicationContext() and inject from there, but skipping the intermediate layers without any option for something in between is inconsistent with the rest of our design, and probably confusing to users even if it works.
This reinforces the opinion expressed in Vasily's answer.
To add further, people often seem to want to inject model-layer dependencies inside their custom views. This is a bad idea as it goes against the software engineering principle of separation of concerns.
The correct solution for associating a view and a model is to write an adapter like the adapters for RecyclerView and ListView. You can inject the model-layer dependency at the Fragment or Presenter level and set the adapter there.

Port from Dagger 2 to Android Dagger 2.11

I cannot get my head around how to setup a couple of things when porting the code from Dagger 2 to Android Dagger 2.11. In Dagger 2 the setup was something like this:
public class App extends Application {
#Override
public void onCreate() {
super.onCreate();
this.initializeInjector();
}
private void initializeInjector() {
//this class should be auto-generated by Dagger on build
this.applicationComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(this))
.netModule(new NetModule())
.build();
}
public ApplicationComponent getApplicationComponent() {
return this.applicationComponent;
}
}
You then had access to the applicationComponent and you could inject any object by using the:
getApplicationComponent().inject(MyCustomObject);
In Android Dagger 2.11 you don't do that anymore. For Activities and Fragments you can inject with the AndroidInjector.inject() method but what about other types? Let's look at an example below. We have a JobManager that can post jobs. The jobs are persisted to a file and when they should be posted they are first deserialized. The problem is that its dependencies are not set of course. So the question is: How to do that?
public class JobManager {
private Context context;
#Inject
public JobManager(Context context) {
this.context = context;
}
public void postJob(String jobId) {
MyJob myJob = deserializePersistedJobFromFile(jobId);
//((App) context).getApplicationComponent().inject(myJob); //This was the old way of doing injection
AndroidInjector.inject(myJob); //This doesn't work - what to do now?
}
.
.
.
}
public class MyJob {
#Inject
ApiService apiService;
.
.
.
}
You can get Dagger to inject a MembersInjector<T> and then use that to inject dependencies into your own objects...
public class JobManager {
private Context context;
#Inject
public JobManager(Context context, MembersInjector<MyJob> jobInjector) {
this.context = context;
}
public void postJob(String jobId) {
MyJob myJob = deserializePersistedJobFromFile(jobId);
jobInjector.inject(myJob);
}
.
.
.
}
Is there any problem you experience with the "old" approach that makes you want to move to the "new" one?
I couldn't find one single real advantage in performing dependency injection using the static AndroidInjector class, but it does increase the complexity of the code.
Therefore, if you don't have a very specific reason to move in that direction, I would suggest to stay with the "old" working approach.
As for injection into non-Activity/Fragment classes, I think you shouldn't use DI framework for this. Use Dagger for injection into Application, Activity, Fragment and Service only. More information available in this post: Dependency Injection in Android.
Writing this on a phone so apologies for any typos.
TL;DR Would it not make sense that, MyJob needs an #Inject(ed) constructor that takes the ApiService, rather than a member injection? Is there a reason why MyJob can't have it's own constructor? (Unfamiliar if this is an Android SDK class or not). If that's not the answer then I have another observation that your JobManager seems to do what the JobScheduler does? Unless it's simply a confusion of terms (i.e. both "jobs")
Outside of Android and it's lifecycle uniqueness dependency inversion's most common use is constructor injection. Learning the DI pattern within the Android framework isn't the best introduction and you get caught up in the 'lying to the complier' DI framework functionality that is meant to simply help move off a legacy codebase (c.f. Dagger 1's static injection or Guide's 'private' member injection).
As a side note, I have avoided moving to "Android Dagger" since it seems to go against having modular separation of code. I think I have more to learn here but right now the boilerplate distruption advantage of "Android Dagger" is outweighed by my need for loosely coupled feature modules to support Instant Apps and an altogether more modular code base.
Hope that helps a bit.
I wrote this article which should be helpful to you. It links to the sample code on Github.
https://proandroiddev.com/exploring-the-new-dagger-android-module-9eb6075f1a46
Pay close attention to the AppModule and how it keeps track of the application so you can pass application.getApplicationContext() into constructors for your JobManager
Using dagger android library has advantages :
1) Using dagger violates dependency injection principle that classes shouldn't know about how dependencies are injected, this violation can be fixed using dagger android library
2) Dagger code can be decoupled from android components.
3) Clean code can be achieved as you don't need to initialize dagger components and call inject methods in android components, leading to creation of easy to maintain apps.
You can decouple dagger from android using dagger android components such as DaggerActivity,DaggerApplication, and DaggerFragment and moving AndroidInjection.inject() calls to central location, instead of calling in each and every activity and fragment, by using activity lifecycle callback on application.
You can read detailed explanation about dagger android at
http://www.zoftino.com/android-framework-classes-dependency-injection-using-dagger-android

What are the advantages of using DispatchingAndroidInjector<> and the other dagger.android classes?

I'm working on setting up Dagger 2 into my android project. It is my first time with this framework and everything goes well so far. But I'm seeing different approaches on the way you can set up this framework in your project and I wonder which one is better, because I compare both and for me the result is kind of the same.
I followed this guide: https://github.com/codepath/android_guides/wiki/Dependency-Injection-with-Dagger-2
Searching on Internet all of them use this approach.
It use #Module and #Component to define the dependencies.
and your application ends up like this:
public class MyApp extends Application {
private NetComponent mNetComponent;
#Override
public void onCreate() {
super.onCreate();
// Dagger%COMPONENT_NAME%
mNetComponent = DaggerNetComponent.builder()
// list of modules that are part of this component need to be created here too
.appModule(new AppModule(this)) // This also corresponds to the name of your module: %component_name%Module
.netModule(new NetModule("https://api.github.com"))
.build();
// If a Dagger 2 component does not have any constructor arguments for any of its modules,
// then we can use .create() as a shortcut instead:
// mNetComponent = com.codepath.dagger.components.DaggerNetComponent.create();
}
public NetComponent getNetComponent() {
return mNetComponent;
}
}
But I found another way (I haven't tested it):https://google.github.io/dagger/android.html
And It looks like completely different, using different classes and annotations.
It uses something like this:
#Subcomponent(modules = ...)
public interface YourActivitySubcomponent extends AndroidInjector<YourActivity> {
#Subcomponent.Builder
public abstract class Builder extends AndroidInjector.Builder<YourActivity> {}
}
#Module(subcomponents = YourActivitySubcomponent.class)
abstract class YourActivityModule {
#Binds
#IntoMap
#ActivityKey(YourActivity.class)
abstract AndroidInjector.Factory<? extends Activity>
bindYourActivityInjectorFactory(YourActivitySubcomponent.Builder builder);
}
#Component(modules = {..., YourActivityModule.class})
interface YourApplicationComponent {}
public class YourApplication extends Application implements HasDispatchingActivityInjector {
#Inject DispatchingAndroidInjector<Activity> dispatchingActivityInjector;
#Override
public void onCreate() {
super.onCreate();
DaggerYourApplicationComponent.create()
.inject(this);
}
#Override
public DispatchingAndroidInjector<Activity> activityInjector() {
return dispatchingActivityInjector;
}
}
So, my questions are:
which one is better?
What are the reasons for choosing one approach instead of the other?
The method of setting up Dagger 2 for Android that is now prescribed in official Dagger 2 documentation has a number of advantages and should be preferred. The advantages are just those elaborated there, namely:
Copy-pasting code makes it hard to refactor later on. As more and more developers copy-paste that block, fewer will know what it actually does.
More fundamentally, it requires the type requesting injection (FrombulationActivity) to know about its injector. Even if this is done through interfaces instead of concrete types, it breaks a core principle of dependency injection: a class shouldn’t know anything about how it isinjected.
Let's apply those reasons to your first example.
Reason 1
Assume we have an Activity that wants to use your NetComponent. Let's call it NetActivity. The onCreate(Bundle savedInstanceState) method of that NetActivity will look something like this:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
((MyApp) getApplicationContext()).getNetComponent().inject(this);
}
This code has all the visual appeal of toenail clippings scattered on oatmeal (not my simile) and will end up copy-pasted in all of the injection site Activities where you use NetComponent. If you use more complicated components, such as this example from the docs:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// DO THIS FIRST. Otherwise frombulator might be null!
((SomeApplicationBaseType) getContext().getApplicationContext())
.getApplicationComponent()
.newActivityComponentBuilder()
.activity(this)
.build()
.inject(this);
// ... now you can write the exciting code
}
Even worse. It can easily degenerate into a magical piece of code that must be copied and pasted throughout the injection sites. If it changes, it's easy to forget to update just one site and have your app crash.
Reason 2
One of the great advantages of dependency injection is injection sites need not know or care about their injectors, just as dependencies do not know or care about their dependents. To return to ourNetActivity, we have:
((MyApp) getApplicationContext()).getNetComponent().inject(this);
The Activity "knows" about its injector (NetComponent), and the Activity is now coupled with a concretion MyApp and the method getNetComponent() from the same. If either of these classes changes, NetActivity will have to change as well.
The advantages of following the new way of injection inside Activity and Fragments available in Dagger versions 2.10 and forward are just the opposite of these disadvantages:
You end up with less copy-paste code
Types requesting injection no longer have to know or care about their injectors or the sources of their injectors.
Furthermore, as pointed out in this blog, preferring subcomponents over dependent components reduces the method count of your app.
While using subcomponents may initially seem more difficult, there are some clear advantages. However, for the purposes of learning Dagger dependent components may be initially easier to understand. If the second example is too complicated initially, you can graduate to the preferred method when you have gained finesse.

Android | Dagger 2. Injecting different subclasses into Fragment depending of a condition

I am working with MVP and Dagger 2 DI. I have a Fragment that I reuse in a few activities. I have an interface type for presenter as a property of the Fragment, say MVPPresenter. Depending in which activity the Fragment is being used, I need to inject different presenters into it (each presenter is an implementation of MVPPresenter). So I need a way to inject each implementation of MVPPresenter into the Fragment as I need.
Currently, I have a terrible solution, which works, but it is simply wrong and creates unnecessary objects that are never used. Here is the code:
public class MyFragment {
...
#Inject
public void setPresenter(#NonNull ProfilePresenter presenter) {
if (mAdapter instanceof ProfileAdapter) {
this.presenter = presenter;
}
}
#Inject
public void setPresenter(#NonNull ContactsPresenter presenter) {
if (mAdapter instanceof ContactsAdapter) {
this.presenter = presenter;
}
}
...
}
Here is my Module:
#Module
class PresentersModule {
#Provides
#Singleton
ProfilePresenter ProfilePresenter() {
return new ProfilePresenter();
}
#Provides
#Singleton
ContactsPresenter ContactsPresenter() {
return new ContactsPresenter();
}
}
You see, depending on Adapter type, I assign presenter, or do not. I know this is stupid and all. Problem is that Dagger needs exact type to inject to be specified and Interface type wont work.
What is the proper way of dealing with such cases?
You have, as I see it, three solutions of varying degrees of weight.
Inject two choices as you have now: If you know all of your Fragment's use-cases up front, and you don't need to vary the dependency graphs any more than on a single class, you can do so easily using a similar method to what you have now. My variant uses Providers, which are bound automatically for any object in your graph, so that you don't unnecessarily create whole trees of objects; also, #Inject methods can take an arbitrary parameter list, so you can do all of your method injection in one method if you choose.
#Inject
public void setPresenter(
#NonNull Provider<ContactsPresenter> contactsPresenterProvider,
#NonNull Provider<ProfilePresenter> profilePresenterProvider) {
if (mAdapter instanceof ContactsAdapter) {
this.presenter = contactsPresenterProvider.get();
} else if (mAdapter instanceof ProfileAdapter) {
this.presenter = profilePresenterProvider.get();
}
}
The other two solutions involve multiple components: Instead of saying "there is one way of binding my graph together", you're effectively asking Dagger to generate multiple options for you, which means that your graphs can vary widely but stay consistent. This technique might be more useful if you reuse objects in different ways for different sections of your application, like if you have a Profile section and a Contacts section, each of which using a common A injecting a common B injecting a common C injecting a different D. To consistently support two deep graphs like that, child components are a much better option.
Use component dependencies: As in rst's answer, you can use component dependencies to isolate your fragments. They did a pretty good job of explaining, so I'll not repeat that here. You should be aware, though, that component dependencies can only consume bindings that are exposed on the component you depend on: Even if Foo and Bar are bound on DiComponent, you won't be able to access them from your ProfileComponent or ContactsComponent unless you put Foo getFoo() and Bar getBar() on your DiComponent. (That said, component dependencies don't have to be Dagger components, either; they can be arbitrary types that you implement yourself or let Dagger implement for you.)
Use subcomponents: Though rst alluded to subcomponents, I think they warrant a bit more explaining, particularly because they are a core component of the recently-released dagger.android functionality, and because Fragments and other UI pieces can be difficult to extract with component dependencies—subcomponents implicitly and automatically inherit bindings from the surrounding component, so you don't have to explicitly expose bindings on your DiComponent. See other differences at this SO question.
#Component
public interface DiComponent {
ProfileComponent getProfileComponent(); // Dagger generates implementations
ContactsComponent getContactsComponent(); // as part of DiComponent.
}
#Subcomponent(modules={ContactsModule.class})
public interface ContactsComponent {
void inject(MyFragment myFragment);
}
#Module
public interface ContactsModule {
#Binds MvpPresenter bindMvpPresenter(ContactsPresenter contactsPresenter);
}
#Subcomponent(modules={ProfileModule.class})
public interface ProfileComponent {
void inject(MyFragment myFragment);
}
#Module
public interface ProfileModule {
#Binds MvpPresenter bindMvpPresenter(ProfilePresenter profilePresenter);
}
In the above, the root DiComponent doesn't have a binding for MvpPresenter, so in itself it can't inject MyFragment. However, ProfileComponent and ContactsComponent can, and each will use different graphs configured in the corresponding Modules (but silently inheriting common bindings from DiComponent's modules). If the graphs vary differently further down, like with each MvpPresenter using the same Validator but with a different ProfileValidationRule versus ContactsValidationRule, you could bind ValidationRule to those different classes in your different Modules to get different behavior.
(For completeness, you would usually also have the option to use a factory like AutoFactory and pass in a parameter like the presenter to your specific container like Fragment. However, this is only really an option if you're creating your instances, and not really an option when Android forces a zero-arg public constructor so it can create Fragment instances at will.)
Looking through the names you've given to mvp-presenters, one could conclude, their complementary mvp-views should rather be separated and implemented in different fragments.
But if you wish to maintain things as-is, having only single setPresenter method declared in your fragment, probably the easiest way to deal with your problem would be to introduce separate components with complementary modules for providing desirable presenter implementations.
For this solution to work you would need to adjust your fragment to contain single declaration of setPresenter method with MVPPresenter type as an argument:
#Inject
public void setPresenter(#NonNull MVPPresenter presenter) {
this.presenter = presenter;
}
Afterwards, you'd need to provide components exposing inject(...) method and declaring usage of appropriate module. As those dependency graphs would be dependent on main component instance, they should get their own scope (tied to activity or fragment, depending on what class is actually holding the graph object).
For instance, if you were using DiComponent for providing all your dependencies with scope defined via #Singleton annotation, you'd need to declare #MyFragmentScope annotation and provide components, dependent on above-mentioned DiComponent, in order to declare injectable presenters:
import javax.inject.Scope;
#Scope
public #interface MyFragmentScope {
}
Your dependent components would look like:
#MyFragmentScope
#Component(dependencies = DiComponent.class, modules = ProfileModule.class)
public interface ProfileComponent {
void inject(MyFragment fragment);
}
with complementary module:
#Module
public class ProfileModule {
#Provides
#MyFragmentScope
MVPPresenter providesProfilePresenter() {
return new ProfilePresenter();
}
}
Note: return type is MVPPresenter, not concrete implementation.
Similarly you'd need to create ContactsComponent and ContactsModule for your ContactsPresenter.
Eventually you should use proper component instance to perform the injection. Now instead of using
diComponent.inject(myFragment)
you should use component which would provide desirable dependency.
At this point you would actually have a switch defining which presenter should be used.
In case of ProfilePresenter injecting you'd need to use:
DaggerProfileComponent.builder()
.diComponent(diComponent)
.build()
.inject(myFragment);
Or in case of ContactsPresenter injecting you'd need to use:
DaggerContactsComponent.builder()
.diComponent(diComponent)
.build()
.inject(myFragment);
It's rather common practice to use separate components for smaller parts of application like activities. It's possible to either declare such components as regular dependent ones or as sub components (see #Subcomponent documentation for reference). Starting from Dagger 2.7 there is a new way of declaring Subcomponents via #Module.subcomponents. Due to this fact there's an opportunity to decouple AppComponent from Activities Subcomponents. You may refer to sample GitHub repository from frogermcs for reference. He also has a great complementary blog post on this topic.

Dagger 2 injection in Fragments and swapping Modules

I've started using Dagger 2 and I'm not sure if I'm doing things right as I ran in the following complication:
Let's say I have a HouseModule initialized with a House and a WindowModule initialized with a Window.
Now I have a HouseFragment which is supposed to general Information about the house.
Thus I created a HouseComponent including the HouseModule.
So far so good.
Now there are multiple nested HouseDetailsFragments within the HouseFragment(ViewPager) which show information about the House and the Window.
I created a HouseDetailsComponent including the HouseModule and the WindowModule.
My dependency graph looks like this:
// provides application wide dependencies (Application context, SharedPref, Repository,...)
#Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
}
// provides general activity dependencies (Navigator,... )
#Component(dependencies = ApplicationComponent, modules = {ActivityComponent.class})
public interface ActivityComponent{
void inject(MainActivity mainActivity);
}
// provides house fragment specific dependencies (HousePresenter,...)
#Component(dependencies = ApplicationComponent, modules = {ActivityComponent.class, HouseComponent.class})
public interface HouseComponent extends ActivityComponent {
void inject(HouseFragment fragment);
}
// provides house details fragment specific dependencies (HouseDetailsPresenter,...)
#Component(dependencies = ApplicationComponent, modules = {ActivityComponent.class, HouseComponent.class, WindowComponent.class})
public interface HouseDetailsComponent extends ActivityComponent {
void inject(HouseDetailsFragment detailsFragment);
}
Component creation becomes increasingly complex this way and I wonder how to inject dependencies to the HouseFragment and especially the HouseDetailsFragments best.
e.g. to build the HouseDetailsComponent I have to do the following:
// casting omitted
DaggerHouseDetailsComponent.builder()
.applicationComponent(getActivity().getApplication().getApplicationComponent())
.activityModule(getActivity().getActivityModule())
.houseModule(getParentFragment().getHouseModule())
.windowModule(new WindowModule(window)).build().inject(this);
I dislike the knowledge (and casting) required about parent fragments and activities.
Is there a simpler way to achieve what I want to do? Any other suggestions about the dependency graph?
Also how do I show a different House in the HouseFragment? i figured creating a new HouseModule and then swapping the other out... but how do I do that? There are no accessors afaik.
I've been using submodules to simplify the hierarchy.
Also Dagger 2.11+ supports Android and makes injections for it easier.

Categories

Resources