How to use Dagger 2 in Android

Dagger 2: One of the efficient dependency injection framework.

What is dependency injection?

Wiring classes together. That is one class is dependent on other is a dependency. Passing the object to the class rather than letting it create is Dependency Injection.

Why dependency injection?

It is good for testing. It makes code loosely coupled and easy to move anywhere across the application.

Why Dagger 2?

It is easy and efficient to use. Annotation based. An important aspect of Dagger 2 is that the library generates code for classes annotated with the @Component interface. You can use a class prefixed with Dagger. e.g. TestComponent interface can be used as DaggerTestComponent class. Dagger 2 relies purely on using Java annotation processors and compile-time checks to analyze and verify dependencies.

It is useful to avoid NullPointerException in activity/fragment/service over objects.

How to use dependency injection using Dagger 2?

Dagger 2 is an annotation based dependency injection framework, so everything is wrap up with annotation.

There are some annotations defined to use on different things like @Module annotation on class, @Component on an interface, @Provides on methods, @Inject on variables, parameters, constructors, etc.

Let’s have an example!

Very first thing we will require in our project to start is dependencies. So let’s put it in the build.gradle file of project’s app module.

dependencies {
    //dagger2 dependecies
    compile "com.google.dagger:dagger:2.9"
    annotationProcessor "com.google.dagger:dagger-compiler:2.9"
    provided 'javax.annotation:jsr250-api:1.0'

    //Retrofit dependencies useful to do network calls
    compile 'com.squareup.retrofit2:retrofit:2.0.2'
    compile 'com.squareup.retrofit2:converter-gson:2.0.2'
}

@Module: It signals to Dagger to search within the available methods for possible instance providers.

Now, create a class say, AppModule.java

@Module
public class AppModule {
    Application application;

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

    @Provides
    @Singleton
    Application provideApplication(){
        return application;
    }

}

We will create one more class say NetModule.java

@Module
public class NetModule {

    String mBaseUrl;

    // Constructor needs one parameter to instantiate.
    public NetModule(String baseUrl) {
        this.mBaseUrl = baseUrl;
    }
    //Remember, Dagger will only look for methods annotated with
    //@Provides
    @Provides
    @Singleton
    // Application reference must come from AppModule.class
    SharedPreferences providesSharedPreferences(Application 
                                        application) {
        return PreferenceManager
               .getDefaultSharedPreferences(application);
    }

    @Provides
    @Singleton
    Gson provideGson() {
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy
                                  .LOWER_CASE_WITH_UNDERSCORES);
        return gsonBuilder.create();
    }

    @NonNull
    @Provides
    @Singleton
    Retrofit provideRetrofit(@NonNull Gson gson) {
        Retrofit retrofit = new Retrofit.Builder()
               .addConverterFactory(
                 GsonConverterFactory.create(gson))
                .baseUrl(mBaseUrl)
                .build();
        return retrofit;
    }
}

Now you might get clear idea that what will be the use of the first module. AppModule class provides the Application object which will useful in NetModule class in a provideSharedPreference() method as a parameter.

@Provides: It denotes to Dagger that the method defined just below to the @Provides annotation is the constructor for the return type. In a method with @Provides annotation, all the parameters should come from outside no matter how many parameters you will require. This method will return the object based on Scope.

@Singleton: It is the scope for the objects returned by the method. @Singleton annotation signals to the Dagger compiler that the instance should be created only once in the application.

@Component: Now let’s see how to use @Component annotation,

@Singleton
@Component (modules = {AppModule.class, NetModule.class})
public interface NetComponent {

    void inject(MainActivity activity);
    
    /* Create different inject() method for different         
    activities/fragent/service */
   
    void inject(MyFragment fragment);
    void inject(MyService service);

}

This is nothing but an interface annotated with @Component. It assigns references in our activities, services, or fragments to have access to singletons we earlier defined.

Note that the activities, services, or fragments that can be added should be declared in this interface with individual inject() methods. We can name the method something else but it is recommended to use as it is.

Next step is, build the component. We should do all this work within a Application class since these instances should be declared only once throughout the entire lifespan of the application, remember we have given the Singleton scope.

public class MyApp extends Application {
   private final String TAG = getClass().getSimpleName();
   private static NetComponent netComponent;
    
    @Override
    public void onCreate() {
         super.onCreate();
         /*Add all the list of modules that are part of the 
           component here */
         netComponent = DaggerNetComponent.builder()
                .appModule(new AppModule(this))
                .netModule(new NetModule("http://google.com"))
                .build();

        Log.e(TAG, "onCreate: netComponent = "+netComponent );
    }

    public static NetComponent getNetComponent() {
        return netComponent;
    }
}

DaggerNetComponent is an auto-generated class, Dagger will generate it at compile time.

If a Dagger 2 component does not have any constructor arguments for any of its modules, we can use .create() as a shortcut instead:

netComponent = DaggerNetComponent.create();

How to get the object in Activity/Fragment?

Here is a MainActivity.java class which will call to the Dagger component and gets the injected objects.

public class MainActivity extends AppCompatActivity {
    @Inject
    SharedPreferences sharedPreferences;
    private final String TAG = getClass().getSimpleName();

    @Inject
    InjectConstructor injectConstructor;

    @Inject
    Retrofit retrofit;

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

        MyApp.getNetComponent().inject(this);

        // Here we will get all the injected class's objects here
        Log.e(TAG, "onCreate: sharedPreferences = 
                   "+sharedPreferences );
        Log.e(TAG, "onCreate: injectConstructor = 
                   "+injectConstructor );
        Log.e(TAG, "onCreate: retrofit = "+retrofit );

        /* We are getting InjectConstructor class object without 
         calling its constructor with new keyword and can 
         access its methods too. */
      
        injectConstructor.testIt();

    }

}

Note that Dagger does not support injection into private fields.

public class InjectConstructor {
    private final String TAG = getClass().getSimpleName();

    @Inject
    public InjectConstructor (){
        Log.e(TAG, "InjectConstructor: Inside of Constructor");
    }

    public void testIt(){
        Log.e(TAG, "testIt: Inside a method of 
                 InjectConstructor");
    }
}

If you see, InjectConstructor class is used in above MainAcitivity. What is it? A simple class whose constructor is annotated with @Inject annotation.

If you want to create an instance of a class without calling its constructor with a new keyword, you can just add @Inject annotation above the class’s constructor. Doing this Dagger gets a signal that needs to create an instance for the class, it will create automatically.  You need to add @Inject annotation over the class object declaration while using it in Activity/Fragment/any other classes.

 

Leave a Reply

Your email address will not be published. Required fields are marked *