Easy Android Dagger 2 Architecture
Yeah! Are you an Android geek? Are you a fan of the square? Yep, I’m. Here we are going to implement dagger a butter in Android.
Before getting into a deep pinch, let’s take a look at what dagger 2 does for Android!
Dagger 2:
Dagger is a fully static, compile-time dependency injection framework for Android which helps developers to write optimized code in a way to create Singleton
instances throughout the application using @Provides
and @Inject
annotations. For better understanding, let us segregate the dagger 2 setup into the following steps:
STEP 1: Add the following gradle dependencies into the build.gradle (Module: app)
compile 'com.google.dagger:dagger:2.6'
annotationProcessor 'com.google.dagger:dagger-compiler:2.6'
STEP 2: Here we come! It’s good news for Android folks! Now say ‘No’ to com.neenbedankt.android-apt
plugin support in dependencies for Android Studio gradle build version 2.3.0 and above, since annotationProcessor
solves this purpose.
STEP 3: Create a Dagger Module class with @Module annotation with your desired name. I am gonna name it DaggerModule.java
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import com.takeoffandroid.androidcleandagger2architecture.modules.Dag gerPresenter;
import com.takeoffandroid.androidcleandagger2architecture.modules.DaggerPresenterImpl;
import javax.inject.Named;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class DaggerModule {
private Context context;
public DaggerModule(Application app) {
this.context = app;
}
@Provides
Context providesContext() {
return context;
}
@Provides
@Named("DaggerModule.UserMobile")
String providesSharedPrefValue() {
return "9789010929";
}
@Provides
@Singleton
SharedPreferences providesSharedPreferences(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context);
}
@Provides
@Singleton
DaggerPresenter providesDaggerPresenter(@Named("DaggerModule.UserMobile") String userMobile, SharedPreferences sharedPreferences){
return new DaggerPresenterImpl(userMobile,sharedPreferences);
}
}
Dagger 2 Annotations:
@Module
— This Annotation is used on top of the class to mark the particular class as a Module component. Here I have created DaggerModule.java
and tagging this as a module by using @Module annotation.
@Singleton
— It creates one instance throughout the application. Yeah! It’s a common phenomenon.
@Provides
— It defines methods that provide dependencies.
You can see the below code snippets where I have created @Provides
method for Context and SharedPreferences.
@Provides
@Singleton
SharedPreferences providesSharedPreferences(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context);
}
@Provides
Context providesContext() {
return context;
}
How @Provides
Annotation Works?
It binds the Actual name (Context, SharedPreferences, Retrofit, OkHttpClient, etc.,)with the user-defined method name.
For Example:
providesSharedPreferences()
— provides(user defined method name. It can be provide, provides, etc. But lets fix it to one common global standard provides)
provides + SharedPreferences which in turn provides SharedPreferences access to Activity, Fragment or wherever needed using @Inject
annotation. In this tutorial, we are passing the SharedPreferences instance to presenter implementation.
2. providesContext()
— provides + Context which in turn provides Context access.
@Named
— This annotation is used to tag a particular provides a method of any return type like String, int, Objects, etc. This annotation type accepts String as a key and it can be accessed in any provided method through a unique key.
@Provides
@Named("DaggerModule.UserMobile")
String providesUserMobile() {
return "9789010929";
}
Where “DaggerModule.UserMobile” is the key for the method type.
We’re gonna pass this @Named(“DaggerModule.UserMobile”)
into DaggerPresenterImpl
class.
@Provides
@Singleton
DaggerPresenter providesDaggerPresenter(@Named ("DaggerModule.UserMobile") String userMobile, SharedPreferences sharedPreferences){
return new DaggerPresenterImpl(userMobile,sharedPreferences);
}
Yeah! We’re almost done. Now couple this DaggerModule into Component (DaggerComponent.java)using @Component annotation.
STEP 4: Create an interface for a Component. I am naming it as DaggerComponent in this tutorial.
@Singleton
@Component(modules = {DaggerModule.class})
public interface DaggerComponent {
void inject(MainActivity mainActivity);
}
STEP 5: Last but not least! Now it’s time to bind Dagger 2 into the Application class.
package com.takeoffandroid.androidcleandagger2architecture;
import android.app.Application;
import dagger.Module;
@Module
public class DaggerApplication extends Application {
private DaggerComponent daggerComponent;
@Override
public void onCreate() {
super.onCreate();
daggerComponent = createDaggerComponent();
}
public DaggerComponent getDaggerComponent() {
return daggerComponent == null ? createDaggerComponent() : daggerComponent;
}
private DaggerComponent createDaggerComponent() {
return DaggerDaggerComponent.builder().daggerModule(new DaggerModule(this)).build();
}
public void clearComponent() {
daggerComponent = null;
}
}
Now let’s focus on the key factors where there is no proper documentation to explain this logic behind Dagger 2 implementation.
DaggerDaggerComponent.builder().daggerModule(new DaggerModule(this)).build();
The above code snippet is used to bind Dagger 2 into application. But it is bit messy and hard to resolve issues if you are new to Dagger 2. Let’s split the above snippet into parts as follows
- DaggerDaggerComponent .builder()— Dagger (Common Notation to bind)+ DaggerComponent (Your Dagger Component class)
For Example:
- If your Component name is AppComponent, then it should be DaggerAppComponent
2. daggerModule(new DaggerModule(this)) — Convert your Dagger Module class into camel case characters.
For Example:
In my case, DaggerModule.java is my dagger module class, hence it is daggerModule
If your module name is AppModule.java, then it should be appModule
STEP 6: Let’s inject Dagger 2 in Activity.
((DaggerApplication) getApplication()).getDaggerComponent().inject(MainActivity.this);
Note: It is mandatory to inject Dagger 2 from Component in your Activity or Fragment to make use of Dagger 2 annotations by creating inject method inside your component class with Context like as follows
package com.takeoffandroid.androidcleandagger2architecture;
import javax.inject.Singleton;
import dagger.Component;
@Singleton
@Component(modules = {DaggerModule.class})
public interface DaggerComponent {
void inject(MainActivity mainActivity);
}
LAST STEP: In the Activity or Fragment, use @Inject
method to get the object of the @Provides annotation created in the module. In my case, I am gonna inject DaggerPresenter class to save and retrieve user's mobile number from SharedPreferences
Happy Coding!