Blog

Dagger 2 — Dependency Injection Basics in Android

Category
Software development
Dagger 2 — Dependency Injection Basics in Android

Android Dagger 2 tutorial

I’m sure that most of you reading this blog already have some idea about Dagger 2. Especially if you are an Android developer.

It turns out that many companies require or expect you to know something about Dagger. And there is a reason for that. While Dagger can be very complex, it is also an awesome tool.

Many times in Android development, we rely on objects that need to be initialized. For instance, let’s say you have a simple screen to display a list of movies. So on Android, you will probably have a fragment that lives inside of the activity. That fragment has some Web API client, which is probably powered by Retrofit or some repository to get and cache movies depending on the project requirement.

You probably already figured out that those are dependencies. For instance, the fragment in the activity, the recyclerView adapter, the Web API client or the repository that will live in the fragment needs to be provided. The most straightforward way is just to let each object obtains its own dependencies references.

Dependency injection is a design principle where you are actually responsible for providing object dependencies to a third party via either field, constructor, or method. Does that sound cool to you? Well, maybe not, maybe yes, or at least not yet, right? ;).

Let’s talk about the benefits of using DI. I’m pretty sure that after this, you will find it a bit cooler.

More reusable code — dependencies that are injected can be configured externally, which increases the reusability of that component.

More readable code — it is easier to spot what an object depends on.

More testable code — dependencies can be configured externally to provide a different implementation or a Mock. This increases the testability of your code.

Promote abstractions instead of concretions — it is a good practice to provide abstractions instead of concretions with your dependencies. Although it is possible to provide concretions, DI promotes the use of abstractions and that is a very good thing.

What is Dagger 2 used for?

Dagger 2 is a very popular dependency injection framework on Android, especially when using Java. It is based on the Java Specification Request (JSR) 330.

Unlike other DI frameworks, Dagger 2 works with annotations processors to generate a very easy-to-read code. This makes it great in terms of performance but also very convenient for developers. If you want to, you can see the magic behind it by going through the full traceable code it generated. But, don’t worry. Most people do not even bother with that code. Still, it’s a good thing that it is there, just in case :D.

Now we have a better overview of Dagger. Let’s create a simple movie android application that will fetch a list of popular movies from The Movie Database API using Dagger 2. Easy, right?

Contact block

Contact block

Scope

Dagger 2 introduce Scoping, which is a mechanism of reusing and retaining an object instance during the whole component lifecycle.

So scoping, in other words, would mean telling Dagger 2 to create a local singleton inside a specific component.

With @Singleton scope, Dagger 2 will ensure that any dependency using this scope will be created only once within the same component.

@Singleton, will behave exactly as any custom scope. Still, since it is provided for us by default and uses the name Singleton, it makes more sense to use it for dependencies that will live within the Application level, obviously, right?

Note: If you do not scope your dependency, Dagger 2 will always provide a new instance each time you request it within a component.

First, let’s create 2 scopes for our Movies application, one for our Fragment lifecycle and one for our Activity lifecycle.

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface FragmentScoped {
}Code language: PHP (php)
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScoped {
view rawCode language: PHP (php)

Components and subcomponents

A component in Dagger 2 is a user-defined object which is responsible to glue everything together. It uses provided modules to create and inject dependencies.

A Subcomponent is a component that lives inside another component, like a child component. But it can only have one parent and share its parent dependencies. However, a parent component can have many subcomponents but do not have access to their subcomponent dependencies.

@Singleton as the scope

One of the reasons why you will want to create a subcomponent is because of Scope. Let’s say you have an application component with @Singleton as the scope. Then you create a new Activity component which is a subcomponent of the top level parent component.

You do not really want dependencies that should live only as long as the activity is alive to share the same @Singleton scope as the parent component. Instead, you want to provide a different scope for that activity so that, as soon as the activity dies, so it’s dependencies.

This way, you can save a lot of resources. 🙂 So it is a better approach for this example to just provide a subcomponent for each of your activities with a different scope. For instance, the @ActivityScoped created above. However, the activity would have access to the parent component. Therefore, it’s dependencies :).

Let’s create our custom Application that should extend DaggerApplication

public class MoviesApplication extends DaggerApplication {
 
 }Code language: PHP (php)

Now let’s create our application component.

@Singleton
@Component()
public interface AppComponent extends AndroidInjector<DaggerApplication> {
    @Override
    void inject(DaggerApplication instance);
    @Component.Builder
    interface Builder {
        AppComponent build();
    }
}Code language: PHP (php)

Android Dagger 2 tutorial

AppComponent scope is @Singleton, and we use the annotation @Componenent to tell Dagger 2 that, this interface is a Component.

That’s it, right? Naaaah, a component is really useless without a Module, because it will not know how to get an instance to inject them since a Module is responsible for telling Dagger how to provide dependencies from the dependency graph.

Let’s now create an ApplicationModule which will provide our project singleton instances, like Retrofit, Picasso…


@Module
abstract class ApplicationModule {
    @Singleton
    @Provides
    static Picasso providePicasso(Context context) {
        return new Picasso.Builder(context).build();
    }
    @Singleton
    @Provides
    static Retrofit provideRetrofit(){
        return new Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl(BuildConfig.BASE_URL)
                .build();
    }
    @Singleton
    @Binds
    abstract Context bindContext(Application application);Code language: CSS (css)

@Provides and @Binds are used to register dependencies for injection.

Notice that I used static methods where @Provides are used. Static methods are fast and this way may also be easier for the compiler. It’s a good practice to use a static method with @Provides.

Binds

@Binds is very similar to @Provides, but you can use it when you want to bind an implementation. For example, in the last method, we will bind the Context to the Application. Any object requesting the context will have instead the Application injected. It is best to use @Binds as much as possible. It is much more efficient because it reduces the line of codes created and the object creation (it will generate about 40% less code than @Provides).

While using @Binds, if an object requires some dependencies (field or constructor injection), Dagger 2 will be smart enough to automagically provide those dependencies if they are available in the component :).

Note that: @Binds methods must have only one parameter whose type is assignable to the return type

Picasso required the Context, and since we provide Context already (on bindContext ), Dagger 2 will automagically provide that context to the providePicasso method.

But what about Application on bindContext method, how Dagger will know about it? Well, for now, it doesn’t because we haven’t provided it yet. Fortunately for us, Dagger comes with something called @BindInstace. Sometimes you can end up with an object that is available only at the time you are actually building the component. For instance, the Android Application, by adding @BindInstance to the component builder, will allow that instance to be injected inside the component.

Now we have to update our AppComponent and add @BindInstance to inject our Application inside the component.

Our new AppComponent will look like this now


@Singleton
@Component()
public interface AppComponent extends AndroidInjector<DaggerApplication> {
    @Override
    void inject(DaggerApplication instance);
    @Component.Builder
    interface Builder {
        @BindsInstance
        Builder application(Application application);
        AppComponent build();
    }
}Code language: CSS (css)

Now Dagger is aware of the Application and will be able to provide it when it is needed.

Let’s now create our Activity Module. 🙂 In order to provide the Fragment, Presenter, RecyclerView Adapter, the DataSource to get movies from theMovieDB server…

@Module
public abstract class MainModule {
    @FragmentScoped
    @ContributesAndroidInjector
    abstract MainFragment provideMainFragment();
    @ActivityScoped
    @Binds
    abstract MainContract.Presenter provideMainPresenter(MainPresenter mainPresenter);
    @ActivityScoped
    @Binds
    abstract RecyclerView.Adapter<MainAdapter.MainVH> provideMainAdapter(MainAdapter mainAdapter);
    @ActivityScoped
    @Binds
    abstract DataSource<Movie> provideModieDataSource(MovieRemoteDataSource movieRemoteDataSource);
    @ActivityScoped
    @Provides
    static MovieRemoteDataSource.MovieApi provideMovieApi(Retrofit retrofit) {
        return retrofit.create(MovieRemoteDataSource.MovieApi.class);
    }Code language: CSS (css)

Dagger 2.11 introduce ContributesAndroidInjector, which frees us from creating a bunch of boilerplate code to create a Fragment Subcomponent or an Activity Subcomponent with their respective binding. Now all you have to do is to use the @ContributesAndroidInjector annotation and make your fragment extend DaggerFragment or DaggerActivity in case of an Activity. We will see how to create an activity component below.

We will create, just for the sake of separating concerns, a new appComponent Module that will be responsible for providing Activities subcomponents only.

@Module
abstract class ActivityBindingModule {
    @ActivityScoped
    @ContributesAndroidInjector(modules = MainModule.class)
    abstract MainActivity mainActivity();
}Code language: CSS (css)

That’s it :), same as fragment @ContributesAndroidInjector will do the trick, and we pass our activity module MainModule.class.

Now we need to update our AppComponent with all those modules for Dagger to know about the whole dependencies graph.

@Singleton
@Component(modules = {ApplicationModule.class,
        ActivityBindingModule.class,
        AndroidSupportInjectionModule.class})
public interface AppComponent extends AndroidInjector<DaggerApplication> {
    @Override
    void inject(DaggerApplication instance);
    @Component.Builder
    interface Builder {
        @BindsInstance
        Builder application(Application application);
        AppComponent build();
    }
}Code language: PHP (php)

We had to add the provided AndroidSupportInjectionModule (or AndroidInjectionModule if you are not using Android support library) since we are using DaggerApplication and @ContributesAndroidInjector.

Now we need to init our AppComponent in our MoviesApplication and our updated file will look like this.

public class MoviesApplication extends DaggerApplication {
    @Override
    protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
        return DaggerAppComponent.builder().application(this).build();
    }
}Code language: PHP (php)

And voila! I hope that you found this interesting and that you will use Dagger and this tutorial in your future Android projects. Or why not migrate to Dagger in your existing projects!

Here is source for the Movies application.

You can follow me on Twitter for more good stuff!

CONTACT US

Exceptional ideas need experienced partners.