项目作者: umangburman

项目描述 :
Efficient Approach to Dependency Injection with Dagger2 Android
高级语言: Java
项目地址: git://github.com/umangburman/Dagger2-Android-Efficient-Approach.git
创建时间: 2018-09-23T19:11:59Z
项目社区:https://github.com/umangburman/Dagger2-Android-Efficient-Approach

开源协议:MIT License

下载


Login Example using Efficient Dagger2 - Android Injector

This is a very simple Login Example of Dagger2 - An Efficient Approach in Android. It takes the input from the UI, uses Dagger2 and displays back on the UI efficiently.

This example is for those beginners who want to learn this efficient approach a.k.a Android Injector. One of the primary advantages of Dagger 2 over most other dependency injection frameworks is that its strictly generated implementation (no reflection) means that it can be used in Android applications. However, there are still some considerations to be made when using Dagger within Android applications.

So Let’s Get Started:

  1. What is Dependency Injection (Efficient)?
  2. What are ComponentInjector, AndroidInjector and other components?
  3. How does it work?
  4. Implementation Step-by-Step
  5. Conclusion

What is Dependency Injection (Efficient)?

Answer: Dependency Injection in build upon the concept of Inversion of Control. Which says that a class should get its dependencies from outside. In simple words, no class should instantiate another class but should get the instances from a configuration class.

If a java class creates an instance of another class via the new operator, then it cannot be used and tested independently from that class and is called a hard dependency.

What are ComponentInjector, AndroidInjector and other components?

Answer: One of the central difficulties of writing an Android application using Dagger is that many Android framework classes are instantiated by the OS itself, like Activity and Fragment, but Dagger works best if it can create all the injected objects. Instead, you have to perform members injection in a lifecycle method.

This has a few problems:

  • Copy-pasting code makes it hard to refactor later on. As more and more developers copy-paste that block, fewer will know what it actually does.

  • More fundamentally, it requires the type requesting injection (FrombulationActivity) to know about its injector. Even if this is done through interfaces instead of concrete types, it breaks a core principle of dependency injection: a class shouldn’t know anything about how it is injected.

To overcome these, Dagger has introduced dagger.android from version - 2.10 onwards. The classes in dagger.android offer one approach to simplify this pattern.

  1. AndroidInjectionModule: Contains bindings to ensure the usability of dagger.android framework classes. This module should be installed in the component that is used to inject the Application class.

  2. ContributesAndroidInjector: Generates an AndroidInjector for the return type of this method. The injector is implemented with a Subcomponent and will be a child of the Module’s component. This annotation must be applied to an abstract method in a Module that returns a concrete Android framework type (e.g. FooActivity, BarFragment, MyService, etc). The method should have no parameters.

  3. HasActivityInjector: Provides an AndroidInjector of Activitys.

  4. DispatchingAndroidInjector: Performs members-injection on instances of core Android types (e.g. Activity, Fragment) that are constructed by the Android framework and not by Dagger. This class relies on an injected mapping from each concrete class to an AndroidInjector.Factory for an AndroidInjector of that class. Each concrete class must have its own entry in the map, even if it extends another class which is already present in the map. Calls Object.getClass() on the instance in order to find the appropriate AndroidInjector.Factory.

  5. AndroidInjection: Injects core Android types.

How does it work?

Answer: AndroidInjection.inject() gets a DispatchingAndroidInjector from the Application and passes your activity to inject(Activity). The DispatchingAndroidInjector looks up the AndroidInjector.Factory for your activity’s class (which is YourActivitySubcomponent.Builder), creates the AndroidInjector (which is YourActivitySubcomponent), and passes your activity to inject(YourActivity).

Implementation Step-by-Step

Step1: Adding Implementations in your Gradle File:

  1. def dagger_versions = "2.17"
  2. // Dagger core dependencies
  3. annotationProcessor "com.google.dagger:dagger-compiler:$dagger_versions"
  4. implementation "com.google.dagger:dagger:$dagger_versions"
  5. // Dagger Android dependencies
  6. annotationProcessor "com.google.dagger:dagger-android-processor:$dagger_versions"
  7. implementation "com.google.dagger:dagger-android:$dagger_versions"
  8. implementation "com.google.dagger:dagger-android-support:$dagger_versions"

Step2: Create a new class for View Model as shown below:

  1. public class LoginViewModel {
  2. public String strUsername, strrPassword;
  3. public String getStrUsername() {
  4. return strUsername;
  5. }
  6. public void setStrUsername(String strUsername) {
  7. this.strUsername = strUsername;
  8. }
  9. public String getStrrPassword() {
  10. return strrPassword;
  11. }
  12. public void setStrrPassword(String strrPassword) {
  13. this.strrPassword = strrPassword;
  14. }
  15. }

Step3: Create a new class for AppModule:

  1. import android.app.Application;
  2. import android.content.Context;
  3. import com.example.umangburman.daggerandroidnewapproach.a1.LoginViewModel;
  4. import javax.inject.Singleton;
  5. import dagger.Module;
  6. import dagger.Provides;
  7. @Module
  8. public class AppModule {
  9. @Singleton
  10. @Provides
  11. Context provideContext(Application application) {
  12. return application;
  13. }
  14. @Provides
  15. LoginViewModel provideLoginViewModel() {
  16. return new LoginViewModel();
  17. }
  18. // ........ Other Object Creation Below ......... //
  19. }

Step4: Create a new abstract class ContributesAndroidInjector:

  1. import com.example.umangburman.daggerandroidnewapproach.a2.AppModule;
  2. import com.example.umangburman.daggerandroidnewapproach.a7.MainActivity;
  3. import dagger.Module;
  4. import dagger.android.ContributesAndroidInjector;
  5. @Module
  6. public abstract class ActivityBuilder {
  7. @ContributesAndroidInjector(modules = AppModule.class)
  8. abstract MainActivity bindMainActivity();
  9. }

Step5: Create a new class for DispatchingAndroidInjector:

  1. import android.app.Activity;
  2. import android.app.Application;
  3. import com.example.umangburman.daggerandroidnewapproach.a6.DaggerAppComponent;
  4. import javax.inject.Inject;
  5. import dagger.android.DispatchingAndroidInjector;
  6. import dagger.android.HasActivityInjector;
  7. public class MyApplication extends Application implements HasActivityInjector {
  8. @Inject
  9. DispatchingAndroidInjector<Activity> activityDispatchingAndroidInjector;
  10. @Override
  11. public void onCreate() {
  12. super.onCreate();
  13. DaggerAppComponent.builder()
  14. .application(this)
  15. .build()
  16. .inject(this);
  17. }
  18. @Override
  19. public DispatchingAndroidInjector<Activity> activityInjector() {
  20. return activityDispatchingAndroidInjector;
  21. }
  22. }

Step6: Create an interface for AndroidInjector:

  1. import android.app.Application;
  2. import com.example.umangburman.daggerandroidnewapproach.a2.AppModule;
  3. import com.example.umangburman.daggerandroidnewapproach.a4.ActivityBuilder;
  4. import com.example.umangburman.daggerandroidnewapproach.a5.MyApplication;
  5. import javax.inject.Singleton;
  6. import dagger.BindsInstance;
  7. import dagger.Component;
  8. import dagger.android.AndroidInjectionModule;
  9. import dagger.android.AndroidInjector;
  10. @Singleton
  11. @Component(modules = { AndroidInjectionModule.class, AppModule.class, ActivityBuilder.class })
  12. public interface AppComponent extends AndroidInjector<MyApplication> {
  13. @Component.Builder
  14. interface Builder {
  15. @BindsInstance
  16. Builder application(Application application);
  17. AppComponent build();
  18. }
  19. void inject(MyApplication application);
  20. }

Step7: Setup Main Activity:

  1. import android.annotation.SuppressLint;
  2. import android.os.Bundle;
  3. import android.support.v7.app.AppCompatActivity;
  4. import android.view.View;
  5. import android.widget.Button;
  6. import android.widget.EditText;
  7. import android.widget.TextView;
  8. import com.example.umangburman.daggerandroidnewapproach.R;
  9. import com.example.umangburman.daggerandroidnewapproach.a1.LoginViewModel;
  10. import javax.inject.Inject;
  11. import dagger.android.AndroidInjection;
  12. public class MainActivity extends AppCompatActivity {
  13. @Inject
  14. LoginViewModel loginViewModel;
  15. private EditText txtEmail, txtPassword;
  16. private TextView lblEmail, lblPassword;
  17. private Button btnLogin;
  18. @SuppressLint("SetTextI18n")
  19. @Override
  20. protected void onCreate(Bundle savedInstanceState) {
  21. super.onCreate(savedInstanceState);
  22. AndroidInjection.inject(this);
  23. setContentView(R.layout.activity_main);
  24. txtEmail = findViewById(R.id.txtEmailAddress);
  25. txtPassword = findViewById(R.id.txtPassword);
  26. lblEmail = findViewById(R.id.lblEmailAnswer);
  27. lblPassword = findViewById(R.id.lblPasswordAnswer);
  28. btnLogin = findViewById(R.id.btnLogin);
  29. btnLogin.setOnClickListener(new View.OnClickListener() {
  30. @Override
  31. public void onClick(View v) {
  32. String Email = txtEmail.getText().toString().trim();
  33. String Password = txtPassword.getText().toString().trim();
  34. loginViewModel.setStrUsername(Email);
  35. loginViewModel.setStrrPassword(Password);
  36. lblEmail.setText(loginViewModel.getStrUsername());
  37. lblPassword.setText(loginViewModel.getStrrPassword());
  38. }
  39. });
  40. }
  41. }

Finally, your activity_main.xml:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. tools:context=".a7.MainActivity">
  8. <android.support.v4.widget.NestedScrollView
  9. android:layout_width="0dp"
  10. android:layout_height="0dp"
  11. android:isScrollContainer="true"
  12. app:layout_constraintBottom_toBottomOf="parent"
  13. app:layout_constraintEnd_toEndOf="parent"
  14. app:layout_constraintHorizontal_bias="0.6"
  15. app:layout_constraintStart_toStartOf="parent"
  16. app:layout_constraintTop_toTopOf="parent"
  17. app:layout_constraintVertical_bias="0.0">
  18. <android.support.constraint.ConstraintLayout
  19. android:layout_width="match_parent"
  20. android:layout_height="match_parent"
  21. tools:context=".View.MainActivity">
  22. <TextView
  23. android:id="@+id/lblTitle"
  24. android:layout_width="0dp"
  25. android:layout_height="wrap_content"
  26. android:layout_marginEnd="8dp"
  27. android:layout_marginStart="8dp"
  28. android:layout_marginTop="16dp"
  29. android:lineSpacingExtra="8sp"
  30. android:text="Login Example Using Dagger2"
  31. android:textAlignment="center"
  32. android:textSize="18sp"
  33. android:textStyle="bold"
  34. app:layout_constraintEnd_toEndOf="parent"
  35. app:layout_constraintStart_toStartOf="parent"
  36. app:layout_constraintTop_toTopOf="parent" ></TextView>
  37. <EditText
  38. android:id="@+id/txtEmailAddress"
  39. android:layout_width="wrap_content"
  40. android:layout_height="wrap_content"
  41. android:layout_marginEnd="8dp"
  42. android:layout_marginStart="8dp"
  43. android:layout_marginTop="32dp"
  44. android:ems="10"
  45. android:hint="E-Mail Address"
  46. android:inputType="textEmailAddress"
  47. app:layout_constraintEnd_toEndOf="parent"
  48. app:layout_constraintStart_toStartOf="parent"
  49. app:layout_constraintTop_toBottomOf="@+id/lblTitle" ></EditText>
  50. <EditText
  51. android:id="@+id/txtPassword"
  52. android:layout_width="wrap_content"
  53. android:layout_height="wrap_content"
  54. android:layout_marginEnd="8dp"
  55. android:layout_marginStart="8dp"
  56. android:layout_marginTop="16dp"
  57. android:ems="10"
  58. android:hint="Password"
  59. android:inputType="textPassword"
  60. app:layout_constraintEnd_toEndOf="parent"
  61. app:layout_constraintStart_toStartOf="parent"
  62. app:layout_constraintTop_toBottomOf="@+id/txtEmailAddress" ></EditText>
  63. <Button
  64. android:id="@+id/btnLogin"
  65. android:layout_width="0dp"
  66. android:layout_height="wrap_content"
  67. android:layout_marginEnd="32dp"
  68. android:layout_marginStart="32dp"
  69. android:layout_marginTop="32dp"
  70. android:onClick="@{(v) -> ClickListener.onClick(v)}"
  71. android:text="Click to Login"
  72. android:textSize="18sp"
  73. app:layout_constraintEnd_toEndOf="parent"
  74. app:layout_constraintStart_toStartOf="parent"
  75. app:layout_constraintTop_toBottomOf="@+id/txtPassword" />
  76. <TextView
  77. android:id="@+id/lblTagline"
  78. android:layout_width="wrap_content"
  79. android:layout_height="wrap_content"
  80. android:layout_marginEnd="8dp"
  81. android:layout_marginStart="8dp"
  82. android:layout_marginTop="60dp"
  83. android:text="See the Results With Dagger2"
  84. android:textColor="@android:color/background_dark"
  85. android:textSize="20sp"
  86. app:layout_constraintEnd_toEndOf="parent"
  87. app:layout_constraintStart_toStartOf="parent"
  88. app:layout_constraintTop_toBottomOf="@+id/btnLogin" ></TextView>
  89. <TextView
  90. android:id="@+id/lblEmailAnswer"
  91. android:layout_width="wrap_content"
  92. android:layout_height="wrap_content"
  93. android:layout_marginEnd="8dp"
  94. android:layout_marginStart="8dp"
  95. android:layout_marginTop="8dp"
  96. android:text="---"
  97. android:textColor="@android:color/holo_blue_light"
  98. android:textSize="20sp"
  99. app:layout_constraintEnd_toEndOf="parent"
  100. app:layout_constraintStart_toStartOf="parent"
  101. app:layout_constraintTop_toBottomOf="@+id/lblTagline" ></TextView>
  102. <TextView
  103. android:id="@+id/lblPasswordAnswer"
  104. android:layout_width="wrap_content"
  105. android:layout_height="wrap_content"
  106. android:layout_marginBottom="32dp"
  107. android:layout_marginEnd="8dp"
  108. android:layout_marginStart="8dp"
  109. android:layout_marginTop="8dp"
  110. android:text="---"
  111. android:textColor="@android:color/holo_blue_light"
  112. android:textSize="20sp"
  113. app:layout_constraintBottom_toBottomOf="parent"
  114. app:layout_constraintEnd_toEndOf="parent"
  115. app:layout_constraintStart_toStartOf="parent"
  116. app:layout_constraintTop_toBottomOf="@+id/lblEmailAnswer" ></TextView>
  117. </android.support.constraint.ConstraintLayout>
  118. </android.support.v4.widget.NestedScrollView>
  119. </android.support.constraint.ConstraintLayout>

And, That is it.

Conclusion

Hopefully this guide introduced you to a lesser known yet useful form of Android application dependency injection known as Dagger2 - Efficient Approach.

Feel free to reach me at any time on LinkedIn