Recent Posts

Those who are free of resentful thoughts surely find peace. - Buddha

Dagger2 - Part3

Posted on 29th Oct 2017


<-Back to Blogs

Part 2  we implemented the DataManagerDbHelper , SharedPrefsHelper and we modeled the class so that we can retrieve the value from the database.

In next steps we will learn how we can create a Component & how it wire itself in the DemoApplication to generate the dependent object.

Step 7:

Create DemoApplication class that extends android.app.Application


public class DemoApplication extends Application {
   
  protected ApplicationComponent applicationComponent;
   
  @Inject
  DataManager dataManager;
   
  public static DemoApplication get(Context context) {
  return (DemoApplication) context.getApplicationContext();
  }
   
  @Override
  public void onCreate() {
  super.onCreate();
  applicationComponent = DaggerApplicationComponent
  .builder()
  .applicationModule(new ApplicationModule(this))
  .build();
  applicationComponent.inject(this);
  }
   
  public ApplicationComponent getComponent(){
  return applicationComponent;
  }
  }

Add this class in AndroidManifest.xml
<application
...
android:name=".DemoApplication"
...
application>

Notes: This class gets DataManager through DI. The interesting part in this class is the ApplicationComponent . Let’s go on with the steps before we cover this point.

Step 8:

Create class MainActivity

public class MainActivity extends AppCompatActivity {
   
  @Inject
  DataManager mDataManager;
   
  private ActivityComponent activityComponent;
   
  private TextView mTvUserInfo;
  private TextView mTvAccessToken;
   
  public ActivityComponent getActivityComponent() {
  if (activityComponent == null) {
  activityComponent = DaggerActivityComponent.builder()
  .activityModule(new ActivityModule(this))
  .applicationComponent(DemoApplication.get(this).getComponent())
  .build();
  }
  return activityComponent;
  }
   
  @Override
  protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
   
  getActivityComponent().inject(this);
   
  mTvUserInfo = (TextView) findViewById(R.id.tv_user_info);
  mTvAccessToken = (TextView) findViewById(R.id.tv_access_token);
  }
   
  @Override
  protected void onPostCreate(@Nullable Bundle savedInstanceState) {
  super.onPostCreate(savedInstanceState);
  createUser();
  getUser();
  mDataManager.saveAccessToken("ASDR12443JFDJF43543J543H3K543");
   
  String token = mDataManager.getAccessToken();
  if(token != null){
  mTvAccessToken.setText(token);
  }
  }
   
  private void createUser(){
  try {
  mDataManager.createUser(new User("Ali", "1367, Gurgaon, Haryana, India"));
  }catch (Exception e){e.printStackTrace();}
  }
   
  private void getUser(){
  try {
  User user = mDataManager.getUser(1L);
  mTvUserInfo.setText(user.toString());
  }catch (Exception e){e.printStackTrace();}
  }
  }


We have to provide the dependencies expressed in the DemoApplication class. This class needs DataManager and to provide this class we have to provide the dependencies expressed by DataManager , which as mentioned in the constructor are ContextDbHelper, and SharedPrefsHelper . We then move further in the graph. 

Also create activity_main.xml

  <xmlns:tools="http://schemas.android.com/tools"
  android:id="@+id/activity_main"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:paddingBottom="@dimen/activity_vertical_margin"
  android:paddingLeft="@dimen/activity_horizontal_margin"
  android:paddingRight="@dimen/activity_horizontal_margin"
  android:paddingTop="@dimen/activity_vertical_margin"
  android:gravity="center"
  android:orientation="vertical">
   
  <TextView
  android:id="@+id/tv_user_info"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:textColor="@android:color/black"
  android:padding="10dp"/>
   
  <TextView
  android:id="@+id/tv_access_token"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:textColor="@android:color/black"
  android:padding="10dp"/>
 

To provide the dependency for a class we have to create a Module class. This class defines the methods that provide the dependency. A Module class is identified by @Module and the dependency provider method in identified by @Provides .Now let’s hold on for some time and review the Dagger2.

  1. We then have to create an interface that serves as a connection between a class that expresses the dependency through @Inject and a class that provides the dependency i.e. annotated with @Module .
  2. In order to figure out the dependencies that a Module has to provide, we have to scan all the classes in the graph that needs to be provided with dependencies and then figure out the least number of objects that has to be provided.

Let’s move back to the example steps to understand the above statements.

Step 9:

  1. Context has to be ApplicationContext
  2. DbHelper needs ContextdbName, and version. This does not have any further branching.
  3. SharedPrefsHelper needs SharedPreferences

We now accumulate the superset of all these dependencies, which turn out to be: ContextdbNameversion, and SharedPreferences

Now to provide these dependencies we create ApplicationModule

@Module
public class ApplicationModule {

private final Application mApplication;

public ApplicationModule(Application app) {
mApplication = app;
}

@Provides
@ApplicationContext
Context provideContext() {
return mApplication;
}

@Provides
Application provideApplication() {
return mApplication;
}

@Provides
@DatabaseInfo
String provideDatabaseName() {
return "demo-dagger.db";
}

@Provides
@DatabaseInfo
Integer provideDatabaseVersion() {
return 2;
}

@Provides
SharedPreferences provideSharedPrefs() {
return mApplication.getSharedPreferences("demo-prefs", Context.MODE_PRIVATE);
}
}

Note: We have annotated this class with @Module and all the methods with @Provides .

The @Module annotation tells Dagger that the ApplicationModule class will provide dependencies for a part of the application. It is normal to have multiple Dagger modules in a project, and it is typical for one of them to provide app-wide dependencies.

Let’s explore this class:

  1. In the constructor, we have passed the Application instance. This instance is used to provide other dependencies. We’ve added a private field to hold a reference to the application object, a constructor to configure application, and a provideContext() method that returns the application object. Notice that there are one more Dagger annotations on that method: @Provides.
  2. The @Provides annotation tells Dagger that the method provides a certain type of dependency, in this case, a Context object. When a part of the app requests that Dagger inject a Context, the @Provides annotation tells Dagger where to find it.
  3. This class provides all the dependencies that we listed in the above step.

Step 10:

Components

Now that you have a Dagger module that contains a dependency that can be injected, how do you use it?

That requires the use of another Dagger annotation, @Component. We create a Component which links the DemoApplication dependency and the ApplicationModule


@Singleton
  @Component(modules = ApplicationModule.class)
  public interface ApplicationComponent {
   
  void inject(DemoApplication demoApplication);
   
  @ApplicationContext
  Context getContext();
   
  Application getApplication();
   
  DataManager getDataManager();
   
  SharedPrefsHelper getPreferenceHelper();
   
  DbHelper getDbHelper();
   
  }

Notes: ApplicationComponent is an interface that is implemented by Dagger2. Using @Component we specify the class to be a Component. You’ve told Dagger that ApplicationComponent is a singleton component interface for the app. The @Component annotation takes a list of modules as an input, and you’ve added ApplicationModule to the list.

The component is used to connect objects to their dependencies, typically by use of overridden inject()methods. It takes the place of the reflective object graph in the original version of Dagger. In order to use the component, it must be accessible from the parts of the app that need injection. Here we have written a method inject where we pass the DemoApplicationinstance. Why do we do it?

When the dependencies are provided through field injection i.e. @inject on the member variables, we have to tell the Dagger to scan this class through the implementation of this interface. This class also provides methods that are used to access the dependencies that exist in the dependency graph.

Next part4 here we would learn how the dependenent object gets generated in DaggerApplicationComponent when we provide the ApplicationModule class to it  to construct the dependencies.


<-Back to Blogs

Categories

Good, better, best. Never let it rest. Untill your good is better and your better is best. - St. Jerome

© SOFTHINKERS 2013-18 All Rights Reserved. Privacy policy