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
// 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
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
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
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
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
@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
<?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
Thanks for your valuable tutorials.. Please publish a unit testing tutorials ….
I miss some real sample how to get Dependencies, like getting a class or something else from DI.
Are their any upcomming Tutorials?
actually, in draft