Dagger 2 – about (sub)components in a few words

Dagger 2 – about (sub)components in a few words

When getting into the subject of dependency injection, we need to understand numerous new techniques that enable us to control created objects. Dagger allows developers to declare interfaces that will handle that. We can create an interface that will be a component or a subcomponent. What is the difference?

Dagger 2 – components or subcomponents?

One of the first decisions we have to make when integrating Dagger (details of its integration were already described on our blog), will be choosing between components and subcomponents. By design, these two components are assigned the same task.

They define modules that will deliver dependencies, declare the scope of their availability and provide a functionality that enables dependency injection.

Before we look at the differences, let us first revise what does a declaration of a basic component look like:

@Singleton
@Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
}

The interface will be treated by the Dagger pre-compiler as a component, thanks to @Component annotation. Keep in mind that each project must have at least one base component.

Component

The base component was described in the previous paragraph. When declaring consecutive components we don’t need to change anything in it. However, we will frequently create objects that will be needed later. By default, any objects created in one module are not visible in other. To share the object we must declare in the component that the object is shared (important is the type returned by the function, not its name):

@Singleton
@Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
    Application application();
}

Next, we need to declare a derivative component that is dependent on it:

@PerActivity
@Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class)
public interface ActivityComponent {

    void inject(ComponentActivity activity);

}

Thanks to assigning the ApplicationComponent class to the dependencies variable in the annotation of the component, we can now use all the objects shared by it. In our case, it is the Application object.

Subcomponent

Declaration of sub-components is handled a little differently. The base component is involved in the creation of its subcomponents. This means that we have to change it every time we add a new subcomponent. Thanks to this link, we don’t have to worry about sharing facilities of a base component.

By default, all objects that are created in modules of the base component are available in the subcomponents. An example of a declaration of a component with a subcomponent might look like this:

@Singleton
@Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {

    ActivitySubcomponent plus(ActivitySubModule subModule);
}
@PerActivity
@Subcomponent(modules = {ActivitySubModule.class})
public interface ActivitySubcomponent {

    void inject(SubcomponentActivity activity);
}

In the Component, we added a method that takes as an argument a module of subcomponent and returns the same subcomponent. This way, we told the base component that it is supposed to create a subcomponent.

In our code, this way we will get an instance of our component and will be able to perform injection on it. The module itself, which was an argument of the function in the base component, was declared as a module of our subcomponent. It is worth noting that the @Subcomponent annotation allows us only to declare our modules as opposed to @Component, which facilitates adding dependencies through the dependencies variable.

Components and subcomponents

We can build a graph of dependencies in our application using components and subcomponents. They give very similar options for creating both objects and their scopes. The main difference is the way of passing objects between the dependent modules. Using components gives a programmer more control over which objects may be used in the derivative components.

Also important is the fact that we don’t need to add new features to the base component each time, which fits very well with the idea of Open-Closed.

In the case of subcomponents, we immediately have access to all objects of the base component. In most cases, a better practice for our applications would be to use common components. This would make our code cleaner and more resistant to changes. We should use subcomponents in situations when both components are strongly related logically and when a derivative component uses most of the objects of the base component.

Learn more

ConstraintLayout, or not so fast, after all…

Recently, while browsing through news from Android world I came across the concept of ConstraintLayout. It is a new layout delivered by Android and Google, supporting Android versions from API 9 on. Digging into possibilities it is to give, I decided to check how the new Layout Builder behaves and what is ConstraintLayout like in use.

Read more

Android Small Talks: CoordinatorLayout, or one of the strengths of Android Design Support Library

When Android Lollipop entered the market, there was a breakthrough. Google provided us with an extensive library of Android Design Support Library which facilitates creating applications that are compliant with the principles of Material Design. Creating a user interface in accordance with these guidelines introduces our software to the next level of design and user-application interaction.

Read more

Project estimation

Let us know what product you want to build and how we can help you.

Why choose us?

Logo Mobile Trends Awards

Mobile Trends Awards 2021

Winning app in
EVERYDAY LIFE

Nagroda Legalnych Bukmacherów

Legal Bookmakers Award 2019

Best Mobile App

Mobile Trends Awards logo

Mobile Trends Awards 2023

Winning app in MCOMMERCE DEVELOPMENT

23

client reviews

Clutch logo