已經有了 Dagger 2 爲什麼還要使用 DaggerAndroid 呢?關於這一點在谷歌的官方說明文檔:https://google.github.io/dagger//android.html 中已經有了明確的解釋。DaggerAndroid 是谷歌基於 Dagger 2 的一個擴展庫,更適合在 Android 開發中使用。爲了更好的學習 DaggerAndroid,還不瞭解 Dagger 2 的同學建議先學習 Dagger 2:Dagger 2 使用及原理
一、更好的 DaggerAndroid
Dagger 2 雖然優秀,但在 Android 開發中確實會存在一些問題,回顧之前 Dagger 2 的使用,我們必須在 Activity 或 Fragment 的聲明週期方法中添加類似這樣的代碼來完成依賴對象的創建和注入:
DaggerMainComponent.builder()
.mainModule(new MainModule())
.build()
.inject(this);
咋一看可能覺得沒什麼問題,但如果在幾十個甚至幾百個 Activity 或 Fragment 中都添加類似的代碼,這對後期的會維護、擴展還是會帶來一定困難的;這些模板代碼都大同小異,可能都是複製、粘貼,然後簡單的修改下,這並不是一種好的做法,而且無法將其轉移到基類裏,我們更想看到的是每個 Activity 或 Fragment 中不出現類似的配置代碼,即我不關心框架是如何給我注入依賴對象的,減少模板代碼。
爲了解決這樣的問題,就有必要使用 DaggerAndroid。
二、基本使用
1、添加依賴庫
implementation 'com.google.dagger:dagger-android:2.15'
// 如果使用了 Android support libraries 中的相關組件,則需要添加該依賴
implementation 'com.google.dagger:dagger-android-support:2.15'
annotationProcessor 'com.google.dagger:dagger-android-processor:2.15'
// Dagger 2 的編譯時註解處理器(必須)
annotationProcessor 'com.google.dagger:dagger-compiler:2.19'
添加了依賴庫後,接下來我們以 MainActivity 的依賴對象注入爲例。
2、編寫 Subcomponent + Module
首先編寫 MainActivity 對應的 MainActivitySubcomponent 接口,注意泛型參數類型爲要注入的的 MainActivity 類型,同時裏邊的 Builder 抽象類不可缺少:
@Subcomponent(modules = {AndroidInjectionModule.class})
public interface MainActivitySubcomponent extends AndroidInjector<MainActivity> {
@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<MainActivity> {
}
}
創建 MainActivity 對應的 MainActivityModule 類,@Module
註解的subcomponents
屬性值爲前邊創建的 MainActivitySubcomponent 類型,@ActivityKey
註解的屬性值爲需要依賴注入的 MainActivity 類型,同時可以在 MainActivityModule 中定義提供依賴對象的方法,bindMainActivityInjectorFactory()
方法的參數類型就是 MainActivitySubcomponent 內部 Builder 類:
@Module(subcomponents = {MainActivitySubcomponent.class})
public abstract class MainActivityModule {
@Binds
@IntoMap
@ActivityKey(MainActivity.class)
abstract AndroidInjector.Factory<? extends Activity>
bindMainActivityInjectorFactory(MainActivitySubcomponent.Builder builder);
@Provides
static FlowerBean provideFlower() {
return new FlowerBean("rose", "red");
}
}
3、編寫全局的 Component
這個 AppComponent 會在自定義 Application 中用到,注意modules
屬性的參數,AndroidInjectionModule
主要提供 DaggerAndroid 核心組件,必須配置,如果使用了 Android support libraries 則需要配置AndroidSupportInjectionModule
,MainActivityModule
則是我們自定義的,提供執行的依賴對象:
@Component(modules = {
AndroidInjectionModule.class,
AndroidSupportInjectionModule.class,
MainActivityModule.class
})
public interface AppComponent {
void inject(App app);
}
4、自定義 Application
這是關鍵的一步,自定義 Application 實現 HasActivityInjector 接口,實現activityInjector()
接口,返回值爲由框架負責注入的dispatchingActivityInjector
對象,底層通過DaggerAppComponent.create().inject(this)
會完成dispatchingActivityInjector
的依賴注入,這個也是依賴注入的準備階段,必不可少。注意DaggerAppComponent
是項目編譯後纔會有的。
dispatchingActivityInjector
是什麼,有什麼用呢?不看編譯後生成的代碼是不知道的,這個後邊說。
public class App extends Application implements HasActivityInjector {
@Inject
DispatchingAndroidInjector<Activity> dispatchingActivityInjector;
@Override
public void onCreate() {
super.onCreate();
DaggerAppComponent.create().inject(this);
}
@Override
public AndroidInjector<Activity> activityInjector() {
return dispatchingActivityInjector;
}
}
5、編寫 MainActivity
聲明需要依賴注入的 flower 對象,這個和 Dagger 2 是一樣的,然後完成調用AndroidInjection.inject(this)
會在底層完成對象的創建和注入。
注意AndroidInjection.inject(this)
需要寫在super.onCreate(savedInstanceState)
之前。
public class MainActivity extends AppCompatActivity {
@Inject
FlowerBean flower;
@Override
protected void onCreate(Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e("flower", flower.toString());
}
}
在 Fragment 中的使用類似,有興趣的可以參考 demo,鏈接會在文末給出,或參考官方的例子。
三、原理
上邊我在結合官方示例的基礎上,實現了依賴注入。但是整個過程有各種疑問,這個類有啥用,爲啥這樣寫,它們之間有什麼依賴關係。如果看編譯時生成的代碼,肯定一臉懵逼,只能照貓畫虎的寫代碼,出現錯誤都不好找原因。如果不懂原理,真的很難靈活的運用它,這也是 Dagger 2 、DaggerAndroid 比較難上手的原因吧。
接下來我們來分析 DaggerAndroid 的依賴注入原理,看一看上邊例子的各個部分是如何一起工作的。
先回顧一下 Dagger 2 的底層原理,當項目編譯時會生成對應的輔助代碼,然後通過類似文章開頭的模板代碼進一步的使用生成的輔助類完成依賴對象的創建和注入。
DaggerAndroid 同樣也是在編譯時生成對應的輔助代碼,但之後需要先在自定義 Application 中通過DaggerAppComponent.create().inject(this)
實現dispatchingActivityInjector
的依賴注入,以保證activityInjector()
方法的返回值有效,這個返回值是依賴注入的關鍵,這也算是依賴注入的準備階段,因爲當我們在 MainActivity 中執行AndroidInjection.inject(this)
方法時需要間接的調用activityInjector()
方法,最終來完成依賴對象的創建和注入,所以我們分兩部分來看。
項目編譯後生成的輔助代碼如下:
1、準備階段
首先看 Application 中的DaggerAppComponent.create().inject(this)
是如何完成dispatchingActivityInjector
的創建和注入。DaggerAppComponent
生成類的源碼直達:DaggerAppComponent
跟隨create()
方法逐步的看,首先是通過Builder
內部類構建一個 DaggerAppComponent 對象:
public final class DaggerAppComponent implements AppComponent {
private Provider<MainActivitySubcomponent.Builder> mainActivitySubcomponentBuilderProvider;
private DaggerAppComponent(Builder builder) {
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
public static AppComponent create() {
return new Builder().build();
}
public static final class Builder {
private Builder() {}
public AppComponent build() {
return new DaggerAppComponent(this);
}
}
}
DaggerAppComponent 的私有構造函數中調用了initialize()
爲 DaggerAppComponent 的mainActivitySubcomponentBuilderProvider
變成變量賦值:
private void initialize(final Builder builder) {
this.mainActivitySubcomponentBuilderProvider =
new Provider<MainActivitySubcomponent.Builder>() {
@Override
public MainActivitySubcomponent.Builder get() {
return new MainActivitySubcomponentBuilder();
}
};
}
mainActivitySubcomponentBuilderProvider
是Provider
類型,通過get()
方法可以返回其保存的MainActivitySubcomponentBuilder
對象的值。繼續看 MainActivitySubcomponentBuilder
的實現:
private final class MainActivitySubcomponentBuilder extends MainActivitySubcomponent.Builder {
......
@Override
public MainActivitySubcomponent build() {
......
return new MainActivitySubcomponentImpl(this);
}
......
}
MainActivitySubcomponentBuilder 就是我們前邊例子(二、2)中接口 MainActivitySubcomponent 內部 Builder 類的子類,重寫了build()
方法並返回了一個 MainActivitySubcomponentImpl 對象:
private final class MainActivitySubcomponentImpl implements MainActivitySubcomponent {
private MainActivitySubcomponentImpl(MainActivitySubcomponentBuilder builder) {}
@Override
public void inject(MainActivity arg0) {
injectMainActivity(arg0);
}
private MainActivity injectMainActivity(MainActivity instance) {
MainActivity_MembersInjector.injectFlower(
instance, MainActivityModule_ProvideFlowerFactory.proxyProvideFlower());
return instance;
}
}
這個類實現了我們自定義的 MainActivitySubcomponent 接口,並重寫了其父類AndroidInjector
的inject()
方法,在injectMainActivity()
中,MainActivityModule_ProvideFlowerFactory.proxyProvideFlower()
會創建一個 Flower 對象,MainActivity_MembersInjector.injectFlower()
方法則會將創建好的 Flower 對象賦值給 MainActivity 中的flower
變量,即依賴注入。
再回到前邊的initialize()
方法,所以mainActivitySubcomponentBuilderProvider
中最終保存了一個MainActivitySubcomponentBuilder
對象,通過該對象可以調用MainActivitySubcomponentImpl
對象的inject()
方法完成依賴對象的注入。
DaggerAppComponent.create()
的核心內容就這些了,然後看其inject(this)
方法:
public final class DaggerAppComponent implements AppComponent {
@Override
public void inject(App app) {
injectApp(app);
}
private App injectApp(App instance) {
App_MembersInjector.injectDispatchingActivityInjector(
instance, getDispatchingAndroidInjectorOfActivity());
return instance;
}
}
DaggerAppComponent 實現了前邊例子(二、3)中的 AppComponent 接口,並重寫了inject()
方法。其中核心方法就是 App_MembersInjector
的injectDispatchingActivityInjector()
方法:
public static void injectDispatchingActivityInjector(
App instance, DispatchingAndroidInjector<Activity> dispatchingActivityInjector) {
instance.dispatchingActivityInjector = dispatchingActivityInjector;
}
即給自定義 Application 中的 dispatchingActivityInjector
成員變量賦值,那這個值是如何被創建的呢,我們看getDispatchingAndroidInjectorOfActivity()
方法:
private DispatchingAndroidInjector<Activity> getDispatchingAndroidInjectorOfActivity() {
return DispatchingAndroidInjector_Factory.newDispatchingAndroidInjector(
getMapOfClassOfAndProviderOfFactoryOf());
}
先看裏邊的getMapOfClassOfAndProviderOfFactoryOf()
方法:
private Map<Class<? extends Activity>, Provider<AndroidInjector.Factory<? extends Activity>>>
getMapOfClassOfAndProviderOfFactoryOf() {
return Collections
.<Class<? extends Activity>, Provider<AndroidInjector.Factory<? extends Activity>>>
singletonMap(MainActivity.class, (Provider) mainActivitySubcomponentBuilderProvider);
}
就是返回了一個 key 爲MainActivity.class
,value 爲 mainActivitySubcomponentBuilderProvider
的 Map,那麼上邊DispatchingAndroidInjector_Factory
類的newDispatchingAndroidInjector()
方法呢:
public static <T> DispatchingAndroidInjector<T> newDispatchingAndroidInjector(
Map<Class<? extends T>, Provider<AndroidInjector.Factory<? extends T>>> injectorFactories) {
return new DispatchingAndroidInjector<T>(injectorFactories);
}
返回了一個DispatchingAndroidInjector
類的對象,所以 DispatchingAndroidInjector 對象中就保存了需要依賴注入的 MainActivity
類型,以及可以實現 MainActivity
依賴注入的mainActivitySubcomponentBuilderProvider
對象的Map,所以我們 Application 中的 dispatchingActivityInjector
成員變量也就有了同樣的信息。
到這裏依賴注入的準備階段就結束了。
2、依賴注入階段
依賴注入階段就是通過 MainActivity 中的AndroidInjection.inject(this)
完成的,我們來看inject(this)
的實現:
public static void inject(Activity activity) {
checkNotNull(activity, "activity");
Application application = activity.getApplication();
if (!(application instanceof HasActivityInjector)) {
throw new RuntimeException(
String.format(
"%s does not implement %s",
application.getClass().getCanonicalName(),
HasActivityInjector.class.getCanonicalName()));
}
AndroidInjector<Activity> activityInjector =
((HasActivityInjector) application).activityInjector();
checkNotNull(activityInjector, "%s.activityInjector() returned null", application.getClass());
activityInjector.inject(activity);
}
即先得到當前 Activity 的 Application,並且 Application 需要實現HasActivityInjector
接口,我們的自定義 Application 符合這樣的條件。然後調用 Application 中重寫的 activityInjector()
方法,所以activityInjector.inject(activity)
就是通過我們 Application 中的dispatchingActivityInjector
對象的inject()
方法,即DispatchingAndroidInjector
類的inject()
方法:
public final class DispatchingAndroidInjector<T> implements AndroidInjector<T> {
@Override
public void inject(T instance) {
boolean wasInjected = maybeInject(instance);
if (!wasInjected) {
throw new IllegalArgumentException(errorMessageSuggestions(instance));
}
}
}
間接調用了maybeInject()
:
public boolean maybeInject(T instance) {
Provider<AndroidInjector.Factory<? extends T>> factoryProvider =
injectorFactories.get(instance.getClass());
if (factoryProvider == null) {
return false;
}
@SuppressWarnings("unchecked")
AndroidInjector.Factory<T> factory = (AndroidInjector.Factory<T>) factoryProvider.get();
try {
AndroidInjector<T> injector =
checkNotNull(
factory.create(instance), "%s.create(I) should not return null.", factory.getClass());
injector.inject(instance);
return true;
} catch (ClassCastException e) {
throw new InvalidInjectorBindingException(
String.format(
"%s does not implement AndroidInjector.Factory<%s>",
factory.getClass().getCanonicalName(), instance.getClass().getCanonicalName()),
e);
}
}
先從準備階段保存的Map中取出 MainActivity 對應的 mainActivitySubcomponentBuilderProvider
對象,然後取出裏邊的值,即 MainActivitySubcomponentBuilder
對象,它實現了AndroidInjector.Factory<T>
接口,我們簡化一下try-catch
裏邊的代碼:
AndroidInjector<T> injector = factory.create(instance);
injector.inject(instance);
factory.create(instance)
最終會調用MainActivitySubcomponentBuilder
的build()
方法來創建MainActivitySubcomponentImpl
對象,所以injector
就是一個MainActivitySubcomponentImpl
對象,所以通過injector.inject(instance)
就調用了前邊準備階段MainActivitySubcomponentImpl
實現類中的inject(MainActivity arg0)
方法,最終完成了 MainActivity 中依賴對象的創建和注入。
四、小結
DaggerAndroid 相比 Dagger 2 的底層依賴注入原理要複雜一些,你寫的代碼越少意味着框架要幫你做的事情越多。通過閱讀源碼,可以更好的理解我們使用框架的每一步,框架底層是如何工作的,而不是簡單的使用。
但是不得不說,DaggerAndroid 的使用過程依舊比較繁瑣,還是會讓很多人望而卻步的,如果你用 Kotlin 語言開發 Android 的話,那麼有更好用、更簡單的依賴注入框架可以選擇,那就是 Kodein-DI
示例代碼在 https://github.com/SheHuan/Dagger2Demo 的 dagger-android 分支上。