Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I use one Component for each Activity in Dagger 2?

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?

like image 336
Tushar Avatar asked Dec 22 '16 20:12

Tushar


People also ask

How do you inject an activity in Dagger 2?

To inject an object in the activity, you'd use the appComponent defined in your Application class and call the inject() method, passing in an instance of the activity that requests injection. When using activities, inject Dagger in the activity's onCreate() method before calling super.

What are the components in Dagger 2?

Components are essentially the glue that holds everything together. They are a way of telling Dagger 2 what dependencies should be bundled together and made available to a given instance so they can be used. They provide a way for a class to request dependencies being injected through their @Inject annotation.

What does Dagger component do?

Dagger components. Dagger can create a graph of the dependencies in your project that it can use to find out where it should get those dependencies when they are needed. To make Dagger do this, you need to create an interface and annotate it with @Component .

How does a Dagger work internally?

To understand it better during a basic course, think module as a provider of dependency and consider an activity or the other class as a consumer. Now to supply dependency from provider to consumer we have a bridge between them, in Dagger, Component work as that specific bridge.


1 Answers

There is some confusion about the role of Components and Modules in Dagger 2 in an Android app.

  1. Components are for grouping similar lifecycles together.

  2. 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();
like image 119
David Rawson Avatar answered Oct 22 '22 14:10

David Rawson