Android & Kotlin

Dagger2 Android Example

Pinterest LinkedIn Tumblr

In this blog, I’m going to explain dependency injection using Dagger2. We learn uses and implementation of Dagger2. In this Dagger2 android example, we are explaining how dagger2 provides solution to tight coupling problem.

Overview

In the following article, We are explaining comprehend used of Dependency Injection. Dependency injection provides an allegiant solution to tight coupling problem. The way it is actually implemented in code had fundamental level is to program against an interface rather than concurrent implementation. If a java class creates an instance of another class via the new operator, then it cannot be used and tested independently from that class and is called a hard dependency.

  // Base structure
    public interface Data{
        List getData();
        void saveData();
    }

    // Low level class implementation
    public class DB implements Data{

        @Override
        public List getData() {
            // querying to data
            return null;
        }

        @Override
        public void saveData() {
           // saving to DB
        }
    }

Understand hard dependency

You can see, we have defined an interface called data, In that interface, we have two methods getData() and saveData(). We call these methods we don’t need to worry about where the data comes from. We have simply using the interface to request the data. It is upon the low-level class like network class to implement the data interface and get our data with this in a mind implementation detail can change. But we can only change the code from low-level classes than implement the interface.

So we have established here that is to better interfaces rather than concurrent classes. For this toward effectively we need to dependency are able to get what the need at runtime. One of the major advantages of dependency injection is that make testing very easy.

   public class OfferManager {
        
        public OfferManager() {
            buyOneGetOne = OfferFactory.getBuyOneGetOne();
        }
        private BuyOneGetOne buyOneGetOne;
        public OfferManager(BuyOneGetOne buyOneGetOne) {
            this.buyOneGetOne = buyOneGetOne;
        }
    }

Suppose you have an object which does something like this init constructor which is to get an object instance by calling a factory. This can be troublesome some when all we want to do is run unit test on our class called OfferManager, especially if the getOneBuyOne something does network access.

So Now, We are looking at mocking getOneBuyOne object but also somehow also intercepting factory call, this is quite awkward or cumbersome instead we pass the object an argument to the constructor. Now we have the problem elsewhere but testing can become a lot easier. To run a test you just create a demo offer object and pass that in. The constructor will look now little bit like test which except argument of offer object.

Solve hard dependency problem

Any application that composed many object that collaborates with each other to perform some useful stuff. Traditionally each object is responsible for obtaining to own references to the dependent object. This lead to highly couple classes and hard to test code.

 //Without Dependency Injection (DI)
    public class Offer {
        BuyOneGetOne buyOneGetOne = new BuyOneGetOneItme1();
        SpecialOffer specialOffer = new SpecialOffer();
        BlackFridayOffer blackFridayOffer = new BlackFridayOffer();
        //rest implementation
    }

    //With Dependency Injection (DI)
    public class Offer{
        BuyOneGetOne buyOneGetOne; /* [Inject the instance of BuyOneGetOneItem1 at runtime]  */
        SpecialOffer specialOffer; /* [Inject the instance of SpecialOffer at runtime] */
        BlackFridayOffer blackFridayOffer; /* [Inject the instance of BlackFridayOffer at runtime]  */
    }

For example, let’s consider the Offer object, Offer depends on condition and number of items to run. The class here is Offer and buyOneGetOne is instantiated by calling a new BuyOneGetOneItme1( ). Here is the Offer object is responsible for creating a dependent object. But what if you want to change the type of dependent object after the initial buyOneGetOne, We need to recreate the buyOneGetOne object with new dependency say BuyOneGetOneItme2, but only the original code author can do it

Then what does Dependency Injection do for us? When using Dependency Injection object are given there dependencies are runtime rather than compile time. So that now we can change the offer object whenever we want. here the SpecialOffer object injected at runtime.

Dagger2

Dagger2 is a dependency injection framework. It provides an allegiant solution to tight coupling problem. Dagger2 based on the Java Specification Request. It uses code generation based on annotations.

Dagger 2 uses the following annotations

  • Provider:- classes with annotated with @Module is responsible for providing an object which can be injected.
  • Consumer:- The @Inject annotation is used to defining a dependency
  • Connector:- A @Component annotated interface defines the connection between the provider and consumer.

Dagger2 Sample Application

Now we will demonstrate how to implement dependency injection using Dagger2 in Android. You have to follow the following steps to setup dependency injection in own project.

Add dependency in build.gradle

We will open the Android Studio and will open app module build.gradle add implementation in dependencies and just click on sync now.

    implementation 'com.google.dagger:dagger-android:2.20'
    implementation 'com.google.dagger:dagger-android-support:2.20' 
    // if you use the support libraries
    annotationProcessor 'com.google.dagger:dagger-android-processor:2.20'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.20'

Create an application module class for Dagger

After gradle has finished building everything we are ready to create some classes which are needed to Dagger2 work. First, we create an application module class named is AppModule add below code

package com.wave.dagger;

import android.app.Application;
import android.content.Context;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;

/**
 * Created on : Feb 09, 2019
 * Author     : AndroidWave
 */
@Module
public class AppModule {

    private Application application;

    public AppModule(Application application) {
        this.application = application;
    }

    @Provides
    @Singleton
    public Context provideContext() {
        return application;
    }

}

This is where dagger keep will keep track of the dependencies. It must be annotated with @Module. So dagger knows this is a module. Later on, we will create module every feature we build. In such module Dagger will look for variable methods and possible instance provider.

    @Provides
    @Singleton
    public Context provideContext() {
        return application;
    }

The methods that exposed the available return type should also be annotated with @Provides decorators. The @Singleton annotation also signals to Dagger compiler that the instance should be created only once in the application. For example, we are specifying the context that uses singleton annotations that can be part of the dependency list.

Create Application Component for Dagger

We need to create an application component where dagger knows where to inject dependency to. In Dagger2 injected class called components. These components assign references in our activity, services, and fragments to have access to the singleton which we are already defined.

We need to annotate this class with app @Component decoration and set the module which defined earlier. the Activities, Services, and Fragment added here in this interface like below code

In src folder just create an interface with named is AppComponent and add below code

package com.wave.dagger;

import javax.inject.Singleton;

import dagger.Component;
/**
 * Created on : Feb 09, 2019
 * Author     : AndroidWave
 */
@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {

    void inject(MainActivity target);
}

Define dagger in Application

We need to define an application object, where dagger will live through-out the entire life spends in the application. We should do all this job within the application class since the instead declared only once. Just create a class that extends application components and add below code.

package com.wave.dagger;

import android.app.Application;

/**
 * Created on : Feb 09, 2019
 * Author     : AndroidWave
 */

public class App extends Application {

    private AppComponent component;

    @Override
    public void onCreate() {
        super.onCreate();

        //needs to run once to generate it
        component = DaggerAppComponent.builder()
                .appModule(new AppModule(this))
                .build();

    }


    public AppComponent getComponent() {
        return component;
    }

}

You are seeing we will overriding onCreate methods here, where will be the component will be instantiated by dagger. We also defined public getComponent() methods which will return AppComponent instance. You notice these methods is highlighted with red with some compilation error.

So In dagger, we have to define every module, we have in app. Later on, we may have app module or other feature modules. right now we have only app module. You have to set application name in AndroidManifest for initializing dagger components.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.wave.dagger">

    <application
        android:name=".App"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        tools:ignore="GoogleAppIndexingWarning">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

This way our application used this class to handle initial initialization

Now we can inject into activity a context.

Now Open the MainActivity and add below code. After that rebuild the project and import necessary class

package com.wave.dagger;

import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import javax.inject.Inject;

/**
 * Created on : Feb 09, 2019
 * Author     : AndroidWave
 */

public class MainActivity extends AppCompatActivity {

    @Inject
    Context context;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ((App) getApplication()).getComponent().inject(this);


    }
}

As you see in an onCreate() methods we need to define this injection, so that dagger components interface we will be used. Notice we are cast getApplication() to our App class. So now we get dagger component and inject activity.

We saw how we can use a Dagger2 framework to implement dependency injection into an Android application.

Download Sample Project- Dagger2 Android Example

I recommend read MVP architect android apps with Dagger2, Retrofit & RxJava

3 Comments

  1. Thanks for your valuable tutorials.. Please publish a unit testing tutorials ….

  2. Programmer Reply

    I miss some real sample how to get Dependencies, like getting a class or something else from DI.
    Are their any upcomming Tutorials?

Write A Comment