距離首次接觸 Dagger2 已經有半年的時間了,從最初的一臉懵逼,到慢慢的熟練使用,這個過程真的感謝 MVPArms,這半年在 MVPArms 真的學到不少東西,由此演變出的 MVVMArms 能夠說是這半年學習的結晶。其中在構建 MVVMArms 的過程當中,採用了最新的 Dagger2.11,更好的支持了 Android 的依賴注入。好了,廢話就說這麼多,下面來經過一個例子來對 Dagger.Android 有更進一步的認識。html
下載源碼一塊兒看會更好!下載源碼一塊兒看會更好!下載源碼一塊兒看會更好!java
DaggerAndroid:github.com/xiaobailong…android
若是你還沒接觸過 Dagger2,能夠看我以前轉載的一篇文章 - Dagger2 學習,裏面概念講得很清晰。
目前大多數文章仍是講解簡單使用 Dagger2,可是對於多 Module 下,怎麼經過 Dagger 管理他們之間的依賴關係,尚未這樣的文章,我會把在 MVVMArms 中探索出的一種 Dagger.Android 多 Module 管理方案分享給你們。git
要在 Android 中使用 Dagger2 , 先添加 Gradle 配置,最新的版本可在 GitHub 找到。這裏使用了 Android Studio 3.0 Beta6。github
//dagger.android
implementation 'com.google.dagger:dagger:2.11'
annotationProcessor 'com.google.dagger:dagger-compiler:2.11'
implementation 'com.google.dagger:dagger-android:2.11'
implementation 'com.google.dagger:dagger-android-support:2.11'
annotationProcessor 'com.google.dagger:dagger-android-processor:2.11'複製代碼
先來看一下幾個關鍵的概念:api
Dagger.Android 能夠有兩種注入方式,下面分別經過 Activity 和 Fragment 來看一下。bash
在整個 Application 的 Component 中添加 AndroidInjectionModule。
AndroidInjectionModule 主要提供 Dagger.Android 組件包,它應該被包含在注入 Application 的 Component 注入器的 modules 中。
此例中爲 AppComponent。app
AppComponent框架
@Singleton
@Component(modules = AndroidInjectionModule.class)
public interface AppComponent {
void inject(MainApp mainApp);
}複製代碼
這樣就能夠確保使用最新的 Dagger.Android。ide
爲 Activity 編寫 Subcomponent,該接口須要繼承 public interface AndroidInjector
MainActivitySubcomponent
@ActivityScope
@Subcomponent(modules = KobeModule.class)//DataModule
public interface MainActivitySubcomponent extends AndroidInjector<MainActivity> {
@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<MainActivity> {
}
}複製代碼
一些須要注入的數據類型能夠包含在 @Subcomponent(modules = {}) 中。
KobeModule
@Module
public class KobeModule {
@ActivityScope
@Provides
public Person provideKobe() {
return new Person("Kobe", 39);
}
}複製代碼
Person
public class Person {
private String name;
private int age;
@Inject
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}複製代碼
接下來,編寫 Activity 的 Module,綁定上一步新建的 Subcomponent,這樣 MainActivitySubcomponent 就會爲 MainActivity 注入 MainActivityModule 中提供的內容。
而後將其添加到全局 Component 中,即上文中的 AppComponent,這樣 AppComponent 就和 MainActivitySubcomponent 創建了聯繫,這是一種繼承關係,即 Subcomponent 爲 Component 的下一級。
MainActivityModule
@Module(subcomponents = MainActivitySubcomponent.class)
public abstract class MainActivityModule {
/** * 第一種注入方式。須要 Subcomponent */
@Binds
@IntoMap
@ActivityKey(MainActivity.class)
abstract AndroidInjector.Factory<? extends Activity>
bindActivityInjectorFactory(MainActivitySubcomponent.Builder builder);
}複製代碼
AppComponent 改寫爲:
@Singleton
@Component(modules = {AndroidInjectionModule.class,
MainActivityModule.class)
public interface AppComponent {
void inject(MainApp mainApp);
}複製代碼
讓 MainApp 實現 HasActivityInjector 接口,並注入 DispatchingAndroidInjector
爲 Activity 提供 AndroidInjector,這是 AndroidInjection.inject(Activity activity) 所須要的,具體見 3.1.6 的源碼解析。
MainApp
public class MainApp extends Application implements HasActivityInjector {
@Inject
DispatchingAndroidInjector<Activity> mActivityInjector;
private AppComponent mAppComponent;
@Override
public void onCreate() {
super.onCreate();
mAppComponent = DaggerAppComponent.builder()
.daggerComponent(getDaggerComponent())
.build();
mAppComponent.inject(this);
}
public AppComponent getAppComponent() {
return mAppComponent;
}
@Override
public AndroidInjector<Activity> activityInjector() {
return mActivityInjector;
}
}複製代碼
最後,在目標 Activity 的 onCreate() 方法中進行注入,須要注意的是應該在 super.onCreate() 調用前注入。
MainActivity
public class MainActivity extends AppCompatActivity {
@Inject
Person mKobe;//依賴注入
public void onCreate(Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
}
}複製代碼
最後不要忘記在 AndroidManifest.xml 中指定 MainApp 。
AndroidInjection.inject() 從 MainApp 得到一個 DispatchingAndroidInjector
AndroidInjection#inject(Activity activity) 源碼以下:
public static void inject(Activity activity) {
checkNotNull(activity, "activity");
Application application = activity.getApplication();
//判斷 Application 是否實現了 HasActivityInjector 接口
if (!(application instanceof HasActivityInjector)) {
throw new RuntimeException(
String.format(
"%s does not implement %s",
application.getClass().getCanonicalName(),
HasActivityInjector.class.getCanonicalName()));
}
//從 Application 中獲取 AndroidInjector 對象,即 DispatchingAndroidInjector<Activity> mActivityInjector
AndroidInjector<Activity> activityInjector =
((HasActivityInjector) application).activityInjector();
checkNotNull(
activityInjector,
"%s.activityInjector() returned null",
application.getClass().getCanonicalName());
//最後注入到 MainActivity 中,此處是在 Dagger 編譯生成的 DaggerAppComponent.MainActivitySubcomponentImpl 類中實現的。
activityInjector.inject(activity);
}複製代碼
Fragment 使用的是v4兼容包中的 android.support.v4.app.Fragment。
因爲在 Activity 依賴注入的第一步已經添加 AndroidInjectionModule,因此這裏能夠直接使用。這種方式實際上是第一種方式的簡化,若是 MainFragmentSubcomponent 和 MainFragmentSubcomponent.Builder 沒有其餘的方法或超類型,以下,
MainFragmentSubcomponent
@FragmentScope
@Subcomponent
public interface MainFragmentSubcomponent extends AndroidInjector<MainFragment> {
@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<MainFragment> {
}
}複製代碼
這時能夠省略 MainFragmentSubcomponent,也就是說,能夠直接不用定義 MainFragmentSubcomponent。
當 Subcomponent 和 它的 Builder 沒有其它方法或超類型時,能夠再也不須要 Subcomponent。
其實Subcomponent 的做用就是生成 AndroidInjector
MainFragmentModule
@Module
public abstract class MainFragmentModule {
/** * 第二種注入方式。當 Subcomponent 和 它的 Builder 沒有其它方法或超類型時,能夠再也不須要 Subcomponent */
@FragmentScope
@ContributesAndroidInjector(modules = JordonModule.class)//DataModule
abstract MainFragment contributeMainFragment();
}複製代碼
一些須要注入的數據類型能夠包含在 @ContributesAndroidInjector(modules = {}) 中。
將MainFragmentModule 裝載到 AppComponent 中:
@Singleton
@Component(modules = {AndroidInjectionModule.class,
MainActivityModule.class,
MainFragmentModule.class})
public interface AppComponent {
void inject(MainApp mainApp);
}複製代碼
讓要依賴注入的目標 Fragment(即 MainFragment) 的宿主 Activity(即 MainActivity) 實現 HasSupportFragmentInjector 接口。
爲 Fragment 提供 AndroidInjector,這是 AndroidInjection.inject(Fragment fragment) 所須要的,具體見 3.2.5 的源碼解析。
MainActivity
public class MainActivity extends AppCompatActivity implements HasSupportFragmentInjector {
@Inject
DispatchingAndroidInjector<Fragment> mFragmentInjector;
//...
public void onCreate(Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
}
@Override
public AndroidInjector<Fragment> supportFragmentInjector() {
return this.mFragmentInjector;
}
}複製代碼
若是使用 android.app.Fragment,Activity 應該實現 HasFragmentInjector 接口,並注入 DispatchingAndroidInjector
。
這一步也能夠在 Application 實現 HasSupportFragmentInjector 接口,相似 3.1.4 所述。
最後,在目標 Fragment 的 onAttach() 方法中進行注入。
MainFragment
public class MainFragment extends Fragment {
@Inject
Person mJordon;//依賴注入
@Override
public void onAttach(Context context) {
super.onAttach(context);
AndroidSupportInjection.inject(this);
}
//...
}複製代碼
Fragment 注入的原理與 Activity 的相似,這裏再強調一遍,其實第二種方式是第一種方式的簡化,使用 @ContributesAndroidInjector 註解來自動生成 Subcomponent。
AndroidSupportInjection#inject(Fragment fragment) 源碼以下:
public static void inject(Fragment fragment) {
checkNotNull(fragment, "fragment");
//獲取 HasSupportFragmentInjector
HasSupportFragmentInjector hasSupportFragmentInjector = findHasFragmentInjector(fragment);
Log.d(
TAG,
String.format(
"An injector for %s was found in %s",
fragment.getClass().getCanonicalName(),
hasSupportFragmentInjector.getClass().getCanonicalName()));
//從 Activity 中獲取 HasSupportFragmentInjector 對象,即 DispatchingAndroidInjector<Fragment> mFragmentInjector
AndroidInjector<Fragment> fragmentInjector =
hasSupportFragmentInjector.supportFragmentInjector();
checkNotNull(
fragmentInjector,
"%s.supportFragmentInjector() returned null",
hasSupportFragmentInjector.getClass().getCanonicalName());
//最後注入到 MainFragment 中,此處是在 Dagger 編譯生成的 DaggerAppComponent.MainFragmentSubcomponentImpl 類中實現的。
fragmentInjector.inject(fragment);
}複製代碼
AndroidSupportInjection#findHasFragmentInjector(Fragment fragment)
private static HasSupportFragmentInjector findHasFragmentInjector(Fragment fragment) {
Fragment parentFragment = fragment;
while ((parentFragment = parentFragment.getParentFragment()) != null) {
if (parentFragment instanceof HasSupportFragmentInjector) {
return (HasSupportFragmentInjector) parentFragment;
}
}
Activity activity = fragment.getActivity();
if (activity instanceof HasSupportFragmentInjector) {
return (HasSupportFragmentInjector) activity;
}
if (activity.getApplication() instanceof HasSupportFragmentInjector) {
return (HasSupportFragmentInjector) activity.getApplication();
}
throw new IllegalArgumentException(
String.format("No injector was found for %s", fragment.getClass().getCanonicalName()));
}複製代碼
由源碼可知,若是須要在 Fragment 中進行依賴注入,能夠有兩種實現方式:一種是宿主 Activity 實現 HasSupportFragmentInjector,另外一種是 Application 實現 HasSupportFragmentInjector。
Service、BroadcastReceiver 和 ContentProvider 的注入方式與此相似。
爲了方便,Dagger.Android 爲咱們提供了一些封裝好的組件類,下面引用官方文檔的一段話,若是有須要,能夠直接使用這些組件類。
Because DispatchingAndroidInjector looks up the appropriate AndroidInjector.Factory by the class at runtime, a base class can implement HasActivityInjector/HasFragmentInjector/etc as well as call AndroidInjection.inject(). All each subclass needs to do is bind a corresponding @Subcomponent. Dagger provides a few base types that do this, such as DaggerActivity and DaggerFragment, if you don’t have a complicated class hierarchy. Dagger also provides a DaggerApplication for the same purpose — all you need to do is to extend it and override the applicationInjector() method to return the component that should inject the Application.
The following types are also included:
Note: DaggerBroadcastReceiver should only be used when the BroadcastReceiver is registered in the AndroidManifest.xml. When the BroadcastReceiver is created in your own code, prefer constructor injection instead.
上面只是簡單的介紹了Dagger.Android 的使用,下面重點來了,仍是將經過一個例子,詳解怎麼利用 Dagger 構建多 Module 依賴關係,從而實現組件化。
這裏,將上述對 Activity 和 Fragment 的依賴注入分離到一個 Library Module 中,利用 Application.ActivityLifecycleCallbacks 和 FragmentManager.FragmentLifecycleCallbacks 監聽,構建全局的依賴注入。
這裏提早提一下本方案下,Dagger 的依賴關係:
DaggerComponent -> AppComponent -> MainActivitySubcomponent/MainFragmentSubcomponent
其中:DaggerComponent 爲 library 的注入器,它的做用域是 @Singleton;
AppComponent 爲主 Module 的全局注入器,它的做用域是 @AppScope,而且 AppComponent 是依賴於 DaggerComponent,也就是說,DaggerComponent 頂級注入器,AppComponent 是主 Module 的注入器;
MainActivitySubcomponent/MainFragmentSubcomponent 是 Activity/Fragment 的注入器,做用域爲 @ActivityScope/@FragmentScope,這裏是 @Subcomponent,經過繼承的方式實現層級依賴,爲 AppComponent 的下一級。
AppScope
@Scope
@Retention(RUNTIME)
public @interface AppScope {
}複製代碼
這裏使用 FragmentLifecycleCallbacks 全局監聽 Fragment 的生命週期,對 Dagger.Android 進行統一注入管理。
DaggerFragmentLifecycleCallbacks
public class DaggerFragmentLifecycleCallbacks extends FragmentManager.FragmentLifecycleCallbacks {
@Inject
public DaggerFragmentLifecycleCallbacks() {
}
@Override
public void onFragmentAttached(FragmentManager fm, Fragment f, Context context) {
super.onFragmentAttached(fm, f, context);
Timber.i(f.toString() + " ---> onFragmentAttached");
AndroidSupportInjection.inject(f);//Dagger.Android Inject for Fragment
}
@Override
public void onFragmentActivityCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {
super.onFragmentActivityCreated(fm, f, savedInstanceState);
Timber.i(f.toString() + " ---> onFragmentActivityCreated");
}
@Override
public void onFragmentDetached(FragmentManager fm, Fragment f) {
super.onFragmentDetached(fm, f);
Timber.i(f.toString() + " ---> onFragmentDetached");
}
}複製代碼
能夠看到,DaggerFragmentLifecycleCallbacks 也是經過 Dagger 進行管理的,在 onFragmentAttached() 方法中進行 Fragment 的依賴注入;而且使用 Timber 打印了幾個關鍵生命週期回調Log。
這裏使用 ActivityLifecycleCallbacks 全局監聽 Activity 的生命週期,對 Dagger.Android 進行統一注入管理。
DaggerActivityLifecycleCallbacks
public class DaggerActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks {
@Inject
DaggerFragmentLifecycleCallbacks mFragmentLifecycleCallbacks;
@Inject
public DaggerActivityLifecycleCallbacks() {
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Timber.w(activity + " ---> onActivityCreated");
AndroidInjection.inject(activity);//Dagger.Android Inject for Activity
if ((activity instanceof HasSupportFragmentInjector || activity.getApplication() instanceof HasSupportFragmentInjector)
&& activity instanceof FragmentActivity) {
((FragmentActivity) activity).getSupportFragmentManager()
.registerFragmentLifecycleCallbacks(mFragmentLifecycleCallbacks, true);
}
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
Timber.w(activity + " ---> onActivityDestroyed");
}
}複製代碼
DaggerComponent
@Singleton
@Component(modules = {AndroidInjectionModule.class,
DaggerModule.class})
public interface DaggerComponent {
Application application();
void inject(DaggerDelegate daggerDelegate);
}複製代碼
其中 DaggerModule 主要提供一些全局依賴,這裏只有一個 provideApplication() 方法,能夠自行添加須要的東西。
DaggerModule
@Module
public class DaggerModule {
private final Application mApplication;
public DaggerModule(Application application) {
mApplication = application;
}
@Singleton
@Provides
public Application provideApplication() {
return this.mApplication;
}
}複製代碼
DaggerDelegate
public class DaggerDelegate {
@Inject
DaggerActivityLifecycleCallbacks mActivityLifecycleCallbacks;
private DaggerComponent mComponent;
private final Application mApplication;
public DaggerDelegate(Application application) {
mApplication = application;
}
public void onCreate() {
Timber.plant(new Timber.DebugTree());
mComponent = DaggerDaggerComponent.builder()
.daggerModule(new DaggerModule(mApplication))
.build();
mComponent.inject(this);
mApplication.registerActivityLifecycleCallbacks(mActivityLifecycleCallbacks);
}
public DaggerComponent getComponent() {
return mComponent;
}
}複製代碼
這裏的 DaggerDelegate 是一個代理類,爲了克服 Application 繼承的問題,經過封裝一個代理類來對 library 的 Dagger 注入進行管理,而後在須要的 Module 裏使用。
至此,Library Module 的依賴注入結構搭建完成。
由上一大節可知,Library Module 中是沒有 Application 的,它是一個 library,若是想使用它,須要在 主 Module 中進行依賴。再說一遍,DaggerComponent 是頂級注入器,AppComponent 主 Module 的全局注入器,它僅限定於 @AppScope。
首先在 app/build.gradle 中添加上節中的 Library Module 依賴:
dependencies {
//library
implementation project(':library')
//...
}複製代碼
AppComponent
@AppScope
@Component(dependencies = DaggerComponent.class,
modules = {AppModule.class,
MainActivityModule.class,
MainFragmentModule.class})
public interface AppComponent {
void inject(MainApp mainApp);
}複製代碼
能夠看到,dependencies = DaggerComponent.class,這就是上文所說的:AppComponent 是依賴於 DaggerComponent,也就是說,DaggerComponent 頂級注入器,AppComponent 是主 Module 的注入器。
其中,AppModule 主要提供主 Module 的一些全局依賴,可自行擴展。
AppModule
@Module
public class AppModule {
private Application mApplication;
public AppModule(Application application) {
mApplication = application;
}
}複製代碼
MainApp
public class MainApp extends Application implements HasActivityInjector {
@Inject
DispatchingAndroidInjector<Activity> mActivityInjector;
private DaggerDelegate mDaggerDelegate;
private AppComponent mAppComponent;
@Override
public void onCreate() {
super.onCreate();
//Library 的依賴注入(頂級)
mDaggerDelegate = new DaggerDelegate(this);
mDaggerDelegate.onCreate();
//注入主 Module 中(該 Module 全局)
mAppComponent = DaggerAppComponent.builder()
.daggerComponent(getDaggerComponent())
.build();
mAppComponent.inject(this);
}
public DaggerComponent getDaggerComponent() {
return mDaggerDelegate.getComponent();
}
public AppComponent getAppComponent() {
return mAppComponent;
}
@Override
public AndroidInjector<Activity> activityInjector() {
return mActivityInjector;
}
}複製代碼
MainApp 是真正進行依賴注入的地方,首先使用上一節 Library Module 中的 DaggerDelegate 進行頂級依賴注入,而後進行 主Module 的依賴注入。須要注意的是,MainApp 必須實現 HasActivityInjector 接口,才能進行 Dagger.Android 注入。
最後不要忘記在 AndroidManifest.xml 中指定 MainApp 。
由第一節的例子可知:當 Subcomponent 和 它的 Builder 沒有其它方法或超類型時,能夠再也不須要手寫 Subcomponent,而是經過 @ContributesAndroidInjector 註解來自動生成。
因此,這裏的 MainActivitySubcomponent/MainFragmentSubcomponent 能夠省略;這樣,MainActivityModule/MainFragmentModule 以下:
MainActivityModule
@Module
public abstract class MainActivityModule {
@ActivityScope
@ContributesAndroidInjector(modules = KobeModule.class)//DataModule
abstract MainActivity contributeMainActivity();
}複製代碼
MainFragmentModule
@Module
public abstract class MainFragmentModule {
@FragmentScope
@ContributesAndroidInjector(modules = JordonModule.class)//DataModule
abstract MainFragment contributeMainFragment();
}複製代碼
KobeModule 和 JordonModule 依舊是第一大節中的,就再也不重複貼代碼了。至此就能夠在 Activity/Fragment 中進行依賴注入了。Dagger.Adnroid 注入是在 Library Module 中的 DaggerActivityLifecycleCallbacks/DaggerFragmentLifecycleCallbacks 完成的,這是一個全局監聽器,使用 DaggerDelegate 在 MainApp 中進行註冊的。
再來強調一下,本方案的 Dagger 層級依賴關係:
DaggerComponent -> AppComponent -> MainActivitySubcomponent/MainFragmentSubcomponent
其中:DaggerComponent 爲 library 的注入器,它的做用域是 @Singleton;
AppComponent 爲主 Module 的全局注入器,它的做用域是 @AppScope,而且 AppComponent 是依賴於 DaggerComponent,也就是說,DaggerComponent 頂級注入器,AppComponent 是主 Module 的注入器;
MainActivitySubcomponent/MainFragmentSubcomponent 是 Activity/Fragment 的注入器,做用域爲 @ActivityScope/@FragmentScope,這裏是 @Subcomponent,經過繼承的方式實現層級依賴,爲 AppComponent 的下一級。
上面兩個例子,第一個介紹了 Dagger.Android 的簡單使用,這是 Dagger2.11 的新姿式;這樣不須要每一個 Activity/Fragment 中再重複手寫一串的依賴注入代碼;而是經過實現 HasActivityInjector/HasSupportFragmentInjector 接口,經過生命週期的監聽,使用 AndroidInjection.inject() 自動注入。
以上是 MVVMArms 框架的基本的 Dagger 層級依賴關係,更詳細的使用能夠查看 MVVMArms。
若是各位有任何疑問,歡迎交流。若是文中有不正之處,也請不吝賜教。
知識分享纔會有快樂,後面我會繼續分解 MVVMArms 的關鍵模塊,若是各位對 MVVMArms 有任何問題或建議,歡迎一塊兒交流。
以上方案的源碼均可以在 Github 查看。
我是 xiaobailong24,您能夠經過如下平臺找到我: