Reputation: 1122
I have the following dependencies in my Android application. What is the best approach to do this in Dagger 2?
Activity A ---- Adapter A and Adapter B and SharedPreferences
Activity B ---- Adapter B and SharedPreferences
Activity C ---- Adapter C and SharedPreferences
Will I have to make a distinct Component for each Activity? Will there have to be three separate Components?
Upvotes: 6
Views: 2989
Reputation: 21487
There is some confusion about the role of Components and Modules in Dagger 2 in an Android app.
Components are for grouping similar lifecycles together.
Modules can be organized along functional lines and for testing (as per the official instructions for testing).
Some of the best examples of this are in the Google Android Architecture Blueprints Github repo. If you examine the source code there, you can see there is one single app-scoped Component (with a lifecycle of the duration of the whole app) and then separate Activity-scoped Components for the Activity and Fragment corresponding to a given functionality in a project. The Activity-scoped Components will, of course, have a lifecycle that corresponds to their respective Activity.
Let's move to your own particular use case. While one activity-scoped component that can inject all the dependencies for Activity A, B, and C may be acceptable for the simple example in the question, the situation will quickly become more complicated if requirements change and Activity A suddenly needs a new dependency with a complicated object graph. You'll then have to create a new Module for the new dependency which will only be useful for one of the three injection sites in your Component. This will, in turn, make things more difficult for testing if you are using a mock Component to test Activity B and Activity C.
Hence, I would argue that from the start it is better to maintain one Component per Activity. Activity-scoped components are cheap and easy to maintain so it is not an issue to err on the side of caution and start with one activity-scoped component per activity.
For the example you have specified, I would create an app-scoped component:
@Component( modules = { SharedPreferencesModule.class } )
@PerApp
interface AppComponent {
SharedPreferences sharedPreferences(Application app);
}
You can have your Activity components become dependent components of the app component. That way they will not have to be concerned with SharedPreferences
since this is bound in the app-component and exposed to dependents:
@Component( dependencies = { AppComponent.class }, modules = { AdapterAModule.class } )
@PerActivityA
interface ActivityAComponent {
}
Note that this is the style encouraged by the dagger.android
package using @ContributesAndroidInjector
:
@PerActivityA
@ContributesAndroidInjector(modules = {ActivityAModule.class})
abstract YourActivity contributeYourActivityInjector();
Upvotes: 10