距离首次接触 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,您能够经过如下平台找到我: