Dragger2是Android應用開發中一個非常優秀的依賴註入框架。本文主要通過結合Google給出的MVP開發案例todo-mvp-dagger(GitHub連接地址:https://github.com/googlesamples/android-architecture/tree/todo- ...
Dragger2是Android應用開發中一個非常優秀的依賴註入框架。本文主要通過結合Google給出的MVP開發案例todo-mvp-dagger(GitHub連接地址:https://github.com/googlesamples/android-architecture/tree/todo-mvp-dagger/),簡要分析一下Dragger2的依賴註入實現過程。
如果是剛入手學習Dragger2,這裡推薦三篇非常不錯的連載文章:http://www.jianshu.com/p/cd2c1c9f68d4,這三篇文章寫得非常用心,而且思路清晰,生動有趣,容易理解。
todo-mvp-dagger在功能上劃分為addedittask,statistics,taskdetail,tasks四個模塊,由於每個模塊除了功能邏輯不同之外,實現方式相差不大,所以我就只分析其中的tasks模塊,其它模塊可參照此模塊的分析流程來分析。
Dragger2的依賴註入是通過Java註解的方式來實現的。Dragger2中提供了@Inject,@Component,@Module,@Provides等一系列註解,通過註解,Dragger2能夠在程式編譯階段利用程式員創建的Java文件,按照編譯模板自動生成對應的.class輔助文件,在這些.class輔助文件中會有相應代碼來自動完成依賴對象的創建。Dragger2正是以此種看似自動化的技術手段來代替手動new對象的過程。如下圖,紅色框中的.class文件就是Tasks模塊在編譯過後自動生成的.class輔助文件。
其實,現在有很多框架都利用了註解的方式,通過在編譯階段生成相應的.class文件來完成依賴註入或者其它某些操作,如阿裡已經開源的路由框架ARouter。
那Dragger2的依賴註入究竟是怎樣的一個過程呢?我們先來看TasksActivity。下麵是TasksActivity的部分代碼。
TasksActivity中依賴了一個對象:mTasksPresenter。mTasksPresenter用@Inject標註,表示在TasksActivity實例化時,mTasksPresenter需要被自動創建,然後註入到TasksActivity實例當中去。此時,我們可能會想,是不是用@Inject標註一下就實現依賴註入了?其實不然。我們看到上圖下方的紅色框中有一段代碼,這段代碼很長,因為DaggerTasksComponent這個類中使用了Builder模式,只要稍微拆分一下明白了,其實這段代碼就做了一件事情,就是調用了TasksComponent的inject()方法,而這裡才是mTasksPresenter真正被實例化的地方。
我們再來看TasksComponent,這是一個很簡單的介面,裡面聲明瞭一個inject(TasksActivity activity)方法:
1 package com.example.android.architecture.blueprints.todoapp.tasks; 2 3 import com.example.android.architecture.blueprints.todoapp.ToDoApplication; 4 import com.example.android.architecture.blueprints.todoapp.data.source.TasksRepositoryComponent; 5 import com.example.android.architecture.blueprints.todoapp.util.FragmentScoped; 6 7 import dagger.Component; 8 9 /** 10 * This is a Dagger component. Refer to {@link ToDoApplication} for the list of Dagger components 11 * used in this application. 12 * <P> 13 * Because this component depends on the {@link TasksRepositoryComponent}, which is a singleton, a 14 * scope must be specified. All fragment components use a custom scope for this purpose. 15 */ 16 @FragmentScoped 17 @Component(dependencies = TasksRepositoryComponent.class, modules = TasksPresenterModule.class) 18 public interface TasksComponent { 19 20 void inject(TasksActivity activity); 21 22 }
有介面,對應的一般就有實現類,TasksComponent的實現類在哪裡呢?我們註意到TasksComponent 被@Component標註,@Component是乾什麼的?@Component是用來標識介面或者抽象類,被@Componen標註的介面或者抽象類,在程式編譯階段會自動生成帶Dragger首碼的.class文件,例如TasksComponent 被@Component標註,就會生成DraggerTasksComponent.class文件。生成的.class文件便是被@Component標註的介面或者抽象類的實現。我們點開DraggerTasksComponent.class,其中的代碼是這樣子的:
1 package com.example.android.architecture.blueprints.todoapp.tasks; 2 3 import com.example.android.architecture.blueprints.todoapp.data.source.TasksRepository; 4 import com.example.android.architecture.blueprints.todoapp.data.source.TasksRepositoryComponent; 5 6 import javax.annotation.Generated; 7 import javax.inject.Provider; 8 9 import dagger.MembersInjector; 10 import dagger.internal.Factory; 11 import dagger.internal.Preconditions; 12 13 @Generated( 14 value = "dagger.internal.codegen.ComponentProcessor", 15 comments = "https://google.github.io/dagger" 16 ) 17 public final class DaggerTasksComponent implements TasksComponent { 18 private MembersInjector<TasksPresenter> tasksPresenterMembersInjector; 19 20 private Provider<TasksRepository> getTasksRepositoryProvider; 21 22 private Provider<TasksContract.View> provideTasksContractViewProvider; 23 24 private Provider<TasksPresenter> tasksPresenterProvider; 25 26 private MembersInjector<TasksActivity> tasksActivityMembersInjector; 27 28 private DaggerTasksComponent(Builder builder) { 29 assert builder != null; 30 initialize(builder); 31 } 32 33 public static Builder builder() { 34 return new Builder(); 35 } 36 37 @SuppressWarnings("unchecked") 38 private void initialize(final Builder builder) { 39 40 this.tasksPresenterMembersInjector = TasksPresenter_MembersInjector.create(); 41 42 this.getTasksRepositoryProvider = 43 new Factory<TasksRepository>() { 44 private final TasksRepositoryComponent tasksRepositoryComponent = 45 builder.tasksRepositoryComponent; 46 47 @Override 48 public TasksRepository get() { 49 return Preconditions.checkNotNull( 50 tasksRepositoryComponent.getTasksRepository(), 51 "Cannot return null from a non-@Nullable component method"); 52 } 53 }; 54 55 this.provideTasksContractViewProvider = 56 TasksPresenterModule_ProvideTasksContractViewFactory.create(builder.tasksPresenterModule); 57 58 this.tasksPresenterProvider = 59 TasksPresenter_Factory.create( 60 tasksPresenterMembersInjector, 61 getTasksRepositoryProvider, 62 provideTasksContractViewProvider); 63 64 this.tasksActivityMembersInjector = 65 TasksActivity_MembersInjector.create(tasksPresenterProvider); 66 } 67 68 @Override 69 public void inject(TasksActivity activity) { 70 tasksActivityMembersInjector.injectMembers(activity); 71 } 72 73 public static final class Builder { 74 private TasksPresenterModule tasksPresenterModule; 75 76 private TasksRepositoryComponent tasksRepositoryComponent; 77 78 private Builder() { 79 } 80 81 public TasksComponent build() { 82 if (tasksPresenterModule == null) { 83 throw new IllegalStateException( 84 TasksPresenterModule.class.getCanonicalName() + " must be set"); 85 } 86 if (tasksRepositoryComponent == null) { 87 throw new IllegalStateException( 88 TasksRepositoryComponent.class.getCanonicalName() + " must be set"); 89 } 90 return new DaggerTasksComponent(this); 91 } 92 93 public Builder tasksPresenterModule(TasksPresenterModule tasksPresenterModule) { 94 this.tasksPresenterModule = Preconditions.checkNotNull(tasksPresenterModule); 95 return this; 96 } 97 98 public Builder tasksRepositoryComponent(TasksRepositoryComponent tasksRepositoryComponent) { 99 this.tasksRepositoryComponent = Preconditions.checkNotNull(tasksRepositoryComponent); 100 return this; 101 } 102 } 103 }
DaggerTasksComponent採用了Builder模式進行設計,實現了inject(TasksActivity activity)方法。DaggerTasksComponent中的代碼有一點點多,而且成員變數都是泛型類對象,看似稍微有點複雜,我們可以整體大概看一下,然後還是從inject(TasksActivity activity)方法的實現入手。inject(TasksActivity activity)的實現很簡單,就一行代碼:
1 tasksActivityMembersInjector.injectMembers(activity);
這一行代碼調用了介面MembersInjector<T>的void injectMembers(T instance)方法,好,接下來我們看看MembersInjector<T>以及其中的void injectMembers(T instance)方法是用來做什麼的。MembersInjector<T>的代碼如下:
1 package dagger; 2 3 /** 4 * Injects dependencies into the fields and methods on instances of type {@code T}. Ignores the 5 * presence or absence of an injectable constructor. 6 * 7 * @param <T> type to inject members of 8 * 9 * @author Bob Lee 10 * @author Jesse Wilson 11 * @since 2.0 (since 1.0 without the provision that {@link #injectMembers} cannot accept 12 * {@code null}) 13 */ 14 public interface MembersInjector<T> { 15 16 /** 17 * Injects dependencies into the fields and methods of {@code instance}. Ignores the presence or 18 * absence of an injectable constructor. 19 * 20 * <p>Whenever the object graph creates an instance, it performs this injection automatically 21 * (after first performing constructor injection), so if you're able to let the object graph 22 * create all your objects for you, you'll never need to use this method. 23 * 24 * @param instance into which members are to be injected 25 * @throws NullPointerException if {@code instance} is {@code null} 26 */ 27 void injectMembers(T instance); 28 }
看過註釋,我們知道了,原來這個介面就是用來將依賴註入到目標實體(即依賴對象所依附的實體,顯然,這裡就是指TasksActivity)當中去。到這裡,我們好像有點眉目了。不著急,我們繼續看MembersInjector<T>的實現。剛剛我們看了DaggerTasksComponent中inject(TasksActivity activity)方法的實現,裡面的tasksActivityMembersInjector對象調用了injectMembers()方法,因此可斷定tasksActivityMembersInjector就是MembersInjector<T>的實現類對象,那麼,tasksActivityMembersInjector是怎麼得來的呢?繼續看DaggerTasksComponent的代碼,發現tasksActivityMembersInjector是這樣被創建的:
1 this.tasksActivityMembersInjector = TasksActivity_MembersInjector.create(tasksPresenterProvider);
TasksActivity_MembersInjector的create()方法創建了tasksActivityMembersInjector。於是,我們再來看TasksActivity_MembersInjector這個類,TasksActivity_MembersInjector代碼如下:
1 package com.example.android.architecture.blueprints.todoapp.tasks; 2 3 import javax.annotation.Generated; 4 import javax.inject.Provider; 5 6 import dagger.MembersInjector; 7 8 @Generated( 9 value = "dagger.internal.codegen.ComponentProcessor", 10 comments = "https://google.github.io/dagger" 11 ) 12 public final class TasksActivity_MembersInjector implements MembersInjector<TasksActivity> { 13 private final Provider<TasksPresenter> mTasksPresenterProvider; 14 15 public TasksActivity_MembersInjector(Provider<TasksPresenter> mTasksPresenterProvider) { 16 assert mTasksPresenterProvider != null; 17 this.mTasksPresenterProvider = mTasksPresenterProvider; 18 } 19 20 public static MembersInjector<TasksActivity> create( 21 Provider<TasksPresenter> mTasksPresenterProvider) { 22 return new TasksActivity_MembersInjector(mTasksPresenterProvider); 23 } 24 25 @Override 26 public void injectMembers(TasksActivity instance) { 27 if (instance == null) { 28 throw new NullPointerException("Cannot inject members into a null reference"); 29 } 30 instance.mTasksPresenter = mTasksPresenterProvider.get(); 31 } 32 33 public static void injectMTasksPresenter( 34 TasksActivity instance, Provider<TasksPresenter> mTasksPresenterProvider) { 35 instance.mTasksPresenter = mTasksPresenterProvider.get(); 36 } 37 }
TasksActivity_MembersInjector正是剛剛我們所看的MembersInjector<T>的一個實現類,TasksActivity_MembersInjector實現了injectMembers(),在injectMembers()的實現中幹了這麼一件事情:
1 instance.mTasksPresenter = mTasksPresenterProvider.get();
哦!原來TasksActivity中的mTasksPresenter是通過mTasksPresenterProvider.get()得來的!此時,迷霧變得逐漸清晰了!接下來再看mTasksPresenterProvider是如何來的。
mTasksPresenterProvider在TasksActivity_MembersInjector的構造方法中被賦值,而TasksActivity_MembersInjector的構造方法是在create()方法中被調用的,於是,我們回到DaggerTasksComponent中調用TasksActivity_MembersInjector的create()方法的地方。找到傳入create()方法的參數tasksPresenterProvider,發現tasksPresenterProvider又是由TasksPresenter_Factory的create()方法創建的。接下來,我們進一步看TasksPresenter_Factory的代碼:
1 package com.example.android.architecture.blueprints.todoapp.tasks; 2 3 import com.example.android.architecture.blueprints.todoapp.data.source.TasksRepository; 4 5 import javax.annotation.Generated; 6 import javax.inject.Provider; 7 8 import dagger.MembersInjector; 9 import dagger.internal.Factory; 10 import dagger.internal.MembersInjectors; 11 12 @Generated( 13 value = "dagger.internal.codegen.ComponentProcessor", 14 comments = "https://google.github.io/dagger" 15 ) 16 public final class TasksPresenter_Factory implements Factory<TasksPresenter> { 17 private final MembersInjector<TasksPresenter> tasksPresenterMembersInjector; 18 19 private final Provider<TasksRepository> tasksRepositoryProvider; 20 21 private final Provider<TasksContract.View> tasksViewProvider; 22 23 public TasksPresenter_Factory( 24 MembersInjector<TasksPresenter> tasksPresenterMembersInjector, 25 Provider<TasksRepository> tasksRepositoryProvider, 26 Provider<TasksContract.View> tasksViewProvider) { 27 assert tasksPresenterMembersInjector != null; 28 this.tasksPresenterMembersInjector = tasksPresenterMembersInjector; 29 assert tasksRepositoryProvider != null; 30 this.tasksRepositoryProvider = tasksRepositoryProvider; 31 assert tasksViewProvider != null; 32 this.tasksViewProvider = tasksViewProvider; 33 } 34 35 @Override 36 public TasksPresenter get() { 37 return MembersInjectors.injectMembers( 38 tasksPresenterMembersInjector, 39 new TasksPresenter(tasksRepositoryProvider.get(), tasksViewProvider.get())); 40 } 41 42 public static Factory<TasksPresenter> create( 43 MembersInjector<TasksPresenter> tasksPresenterMembersInjector, 44 Provider<TasksRepository> tasksRepositoryProvider, 45 Provider<TasksContract.View> tasksViewProvider) { 46 return new TasksPresenter_Factory( 47 tasksPresenterMembersInjector, tasksRepositoryProvider, tasksViewProvider); 48 } 49 }
我們發現,在TasksPresenter_Factory實現的get()方法中,一個匿名TasksPresenter對象被創建,這個匿名對象正是被註入到TasksActivity的依賴對象!
我們再回過頭來看,因為這裡的get()方法其實就是Provider<TasksPresenter>的具體實現,在TasksActivity_MembersInjector中的injectMembers(TasksActivity instance)方法中被TasksActivity_MembersInjector的成員變數mTasksPresenterProvider調用,mTasksPresenterProvider調用get()方法後返回的結果被賦值給TasksActivity實例中的依賴對象mTasksPresenter。
至此,Dragger2中一個完整的依賴註入過程分析就此結束。誠然,本文只是簡單梳理了一下依賴註入的整個流程,對於更深層次的問題,如:Dragger是如何設計.class文件自動生成模板的,自動生成.class文件的具體過程是什麼樣的等等,本文暫時沒有說明,這也是我接下來要做的事情,剛好這幾天也在看ARouter的源碼,發現其中的依賴註入實現和Dragger2差不多,所以,我打算從多個源碼框架中來對比分析和總結Android中的依賴註入實現,待領悟再深入一個層次之後再發一篇總結性文章。