Part 3. Advanced Android Tutorial - Dependency Injection

What is Dependency Injection? 

First of all the term sounds frightening 😛. When I heard the term first, I thought it must be some very difficult design pattern meant only for very advanced developers. Now I can't imagine writing applications without it. So let's see a nice video about Dependency Injection and then we will discuss it further.

Let me bore you at the outset! These are some theories associated with dependency injection which you will find a bit easier to grasp because of the video you just watched. If you have not watched it, please go back and watch it. 

Dependency Injection is a specific form of Inversion of Control. I know you feel like it, but do not pull your hair out yet. Have some patience and read on. So what is Inversion of Control? Inversion of Control has two principles which should not be violated.
  1. The modules of top levels shouldn’t depend on modules of the lower levels. The modules of all levels should depend on abstractions.
  2. The abstractions shouldn’t depend on details. The details should depend on abstractions.
In summary, you should avoid hard dependencies. A dependency is a coupling between two modules or classes of code. This leads to problems because if we make any change in one module, we must make corresponding changes in the coupled module as well. For example, let us look at this code:

public class Scooter {

   private Indicator indicator;

   public Scooter(){
      scooter = new Scooter();
   }
 
   public void turn(){
     .........
      indicator.switchOn();
   } 
}


Now how can we test 'turn' without testing ‘switchOn’? If the test fails, which method is failing? And things get worse if the method saves something in the database or performs an API call. Therefore, a class should not initiate a dependency by itself because it creates a high coupling that will be quite difficult to test. Whenever we create a new instance we introduce a hard dependency. Hard dependency should be avoided if we want to write testable and configurable code.

Solving Hard Dependency

To solve the problem of hard dependency we should make sure that these dependency objects should be “injected” from outside components like factories or builders. Basically, we need a Dependency Injector. Dependency Injector is a special module in our app that is in charge of providing instances of the rest of modules and "inject" their dependencies. So inside a module, we are not creating instances and we can follow the Single Responsibility Principle.

Dependency Injection in Android 

All this sounds very nice. But how do we take advantage of Dependency Injection in Android? Dagger2 is an open-source framework for that purpose. The framework removes a lot of the boilerplate code and also provides a systematic way to apply dependency injection across our Android app. Dagger2 has some advantages which I would like to mention here. Do not worry if you do not understand every point. Once you have an understanding of Dagger2, you can come here and look at these points and agree or disagree with me.
  1. Simple handling of complex dependencies: The big applications have several dependencies. Dagger2 makes it easier to handle dependency injections. 
  2. Code generation through annotations: Dagger2 generates codes required for Dependency Injection through simple annotations. The generated codes are concise and readable. 
  3. Small size of the library
I will discuss Dagger2 in detail in next lesson. But just as a preview of the goodies that Dagger2 offers, look at an example where I inject three dependencies in a Fragment. Once I have object injected in my class, I can use it for making API calls which are defined in one place. (Don't worry if you do not understand the above line. It is only an example.)

public class MobileVerificationProgressFragment extends RxFragment {


 @Inject
 UserPreferenceStore _mPreferenceStore;
 @Inject
 DeviceStore _mDeviceStore;
 @Inject
 IDFCUPIStore _mIDFCStore;

 private SendSMSIfc mActivity;

 BroadcastReceiver mDeliverReceiver;
 BroadcastReceiver mSentReceiver;
        ...............................
}

private void generateOtp() {
     _mIDFCStore.generateOTP(generateOTPReq)
     .compose(this.bindToLifecycle())
     .observeOn(AndroidSchedulers.mainThread())
     .subscribe(new Consumer() 
     .....................
}


No comments:

Powered by Blogger.