告别Dagger2模板代码:DaggerAndroid原理解析

本系列所有文章:

Android 神兵利器Dagger2使用详解(一)基础使用
Android 神兵利器Dagger2使用详解(二)Module&Component源码分析
Android 神兵利器Dagger2使用详解(三)MVP架构下的使用
Android 神兵利器Dagger2使用详解(四)Scope注解的使用及源码分析
告别Dagger2模板代码:DaggerAndroid使用详解
告别Dagger2模板代码:DaggerAndroid原理解析
该系列首发于我的CSDN专栏 :
Android开发:Dagger2详解

概述

距离我的上一篇文章发布以来,有幸收获了一些朋友的认可,我很开心。

在上一篇文章中,我简单叙述了Dagger2这个库目前在Android开发中的一些短板,为什么我们学习Dagger-Android这个拓展库,以及如何使用这个拓展库。

今天我们进行代码分析,看看Dagger-Android是如何基于Dagger2实现一行代码实现所有同类组件依赖注入的。

阅读本文也许您需要准备的

  • 本文可能需要您对Dagger2有一定的了解,包括它内部模板代码生成的一些逻辑。

核心代码

书承上文,我们知道,我们实现依赖注入的代码主要为以下两行:

public class MyApplication extends Application implements HasActivityInjector {

    @Inject
    DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;

    @Override
    public void onCreate() {
        super.onCreate();
        //1.Application级的依赖注入
        DaggerMyAppComponent.create().inject(this);
    }

    @Override
    public AndroidInjector<Activity> activityInjector() {
        return dispatchingAndroidInjector;
    }

}
public class BaseActivity extends AppCompatActivity{

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        //2.Activity级的依赖注入
        AndroidInjection.inject(this);
        super.onCreate(savedInstanceState);
    }
}

抛开这两行,也许我们还有更多疑问:

  • 1.MyApplication中的dispatchingAndroidInjector成员是干嘛的
  • 2.MyApplication实现的HasActivityInjector接口和实现的activityInjector()方法又是干嘛的
  • 3.为什么这样2行依赖注入代码,就能代替之前我们每个Activity都需要写的模板代码呢:
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // DO THIS FIRST. Otherwise frombulator might be null!
    ((SomeApplicationBaseType) getContext().getApplicationContext())
        .getApplicationComponent()
        .newActivityComponentBuilder()
        .activity(this)
        .build()
        .inject(this);
    // ... now you can write the exciting code
  }

直接公布结论:

这里写图片描述
这里写图片描述

这三张图描述了很多东西,我们不需要先去看懂它,我们会随着我们的步骤,一步步分析透彻它,拨开云雾见晴天。、

首先我们分析Application中的这行代码:

DaggerMyAppComponent.create().inject(this);

一、DaggerMyAppComponent.create()原理

我们先点开create()方法,可以看到,无非是初始化了一个DaggerMyAppComponent对象,然后执行了initialize()方法

    public static MyAppComponent create() {
        return new Builder().build();
    }
    
    public static final class Builder {
        private Builder() {
        }

        public MyAppComponent build() {
            return new DaggerMyAppComponent(this);
        }
    }
        
    private DaggerMyAppComponent(Builder builder) {
        assert builder != null;
        initialize(builder);
    }

我们接着看initialize()方法:

private void initialize(final Builder builder) {
    //1
    this.mainActivitySubcomponentBuilderProvider =
            new dagger.internal.Factory<
                    AllActivitysModule_ContributeMainActivitytInjector.MainActivitySubcomponent.Builder>() {
                @Override
                public AllActivitysModule_ContributeMainActivitytInjector.MainActivitySubcomponent.Builder
                get() {
                    return new MainActivitySubcomponentBuilder();
                }
            };

    this.bindAndroidInjectorFactoryProvider = (Provider) mainActivitySubcomponentBuilderProvider;

    this.secondActivitySubcomponentBuilderProvider =
            new dagger.internal.Factory<
                    AllActivitysModule_ContributeSecondActivityInjector.SecondActivitySubcomponent
                            .Builder>() {
                @Override
                public AllActivitysModule_ContributeSecondActivityInjector.SecondActivitySubcomponent
                        .Builder
                get() {
                    return new SecondActivitySubcomponentBuilder();
                }
            };

    this.bindAndroidInjectorFactoryProvider2 = (Provider) secondActivitySubcomponentBuilderProvider;
    //2
    this.mapOfClassOfAndProviderOfFactoryOfProvider =
            MapProviderFactory
                    .<Class<? extends Activity>, AndroidInjector.Factory<? extends Activity>>builder(2)
                    .put(MainActivity.class, bindAndroidInjectorFactoryProvider)
                    .put(SecondActivity.class, bindAndroidInjectorFactoryProvider2)
                    .build();
    //3
    this.dispatchingAndroidInjectorProvider =
            DispatchingAndroidInjector_Factory.create(mapOfClassOfAndProviderOfFactoryOfProvider);
    //4
    this.myApplicationMembersInjector =
            MyApplication_MembersInjector.create(dispatchingAndroidInjectorProvider);
}

这就有点难受了,代码很多,我们一步步慢慢分析。

我们不要一次想着把这些代码彻底读懂,我们首先大概对整个流程有个了解,之后慢慢拆分代码不迟:

    1. 我们可以理解为直接初始化了MainActivitySubcomponentBuilder和SecondActivitySubcomponentBuilder的对象,这个对象能够提供一个对应ActivityComponent的实例化对象,有了这个实例化对象,我们就能够对对应的Activity进行依赖注入。
  1. 这个很明显了,把所有ActivityComponent的实例化对象都存储到一个Map中,然后这个Map通过放入mapOfClassOfAndProviderOfFactoryOfProvider对象中。
  2. 通过mapOfClassOfAndProviderOfFactoryOfProvider初始化dispatchingAndroidInjectorProvider对象
  3. 通过dispatchingAndroidInjectorProvider对象初始化myApplicationMembersInjector对象

好的基本差不多了 我们看看每个步骤都是如何实现的

第1步详细分析

以SecondActivity的这行代码为例:

this.secondActivitySubcomponentBuilderProvider =
            new dagger.internal.Factory<    //1.看这行,实际上是new了一个能提供SecondActivitySubcomponentBuilder()的Provider
                    AllActivitysModule_ContributeSecondActivityInjector.SecondActivitySubcomponent
                            .Builder>() {
                @Override
                public AllActivitysModule_ContributeSecondActivityInjector.SecondActivitySubcomponent
                        .Builder
                get() {
                //2.这个SecondActivitySubcomponentBuilder能干什么呢
                    return new SecondActivitySubcomponentBuilder();
                }
            };
 private final class SecondActivitySubcomponentImpl
            implements AllActivitysModule_ContributeSecondActivityInjector.SecondActivitySubcomponent {
        private MembersInjector<SecondActivity> secondActivityMembersInjector;
        //3.我们点开构造方法,看到实际是走了initialize(builder);
        private SecondActivitySubcomponentImpl(SecondActivitySubcomponentBuilder builder) {
            assert builder != null;
            initialize(builder);
        }

        @SuppressWarnings("unchecked")
        private void initialize(final SecondActivitySubcomponentBuilder builder) {
            //4.实际上是初始化了一个SecondActivity_MembersInjector,这个Injector能够对SecondActivity所需要的对象提供注入
            this.secondActivityMembersInjector =
                    SecondActivity_MembersInjector.create(SecondActivityModule_ProvideNameFactory.create());
        }

        @Override
        public void inject(SecondActivity arg0) {
            //5.我们不难想象,不久后当SecondActivity需要依赖注入,一定会执行这行代码进行对象注入
            secondActivityMembersInjector.injectMembers(arg0);
        }
}

看到这里我们明白了,实际上第一步是ApplicationComponent实例化了所有的ActivityComponent(就是那个能提供SecondActivitySubcomponentBuilder()的Provider)

然后每个ActivityComponent都能提供某个Activity依赖注入所需要的ActivityMembersInjector。

第2步第3步分析

第2步就很简单了,这些ActivityComponent都被放入了一个Map集合中,该集合又放入了apOfClassOfAndProviderOfFactoryOfProvider中,这个Provider实际上也是一个工厂,负责提供该Map的实例化

第3步也很好理解,我们MapProvider工厂交给了就是dispatchingAndroidInjectorProvider去管理。

第4步分析:

实际上我们传入dispatchingAndroidInjectorProvider做了什么呢?

我们看看MyApplication_MembersInjector对象是干嘛的:

//核心代码
public final class MyApplication_MembersInjector implements MembersInjector<MyApplication> {
  private final Provider<DispatchingAndroidInjector<Activity>> dispatchingAndroidInjectorProvider;
  ...
  ...
  ...
  //依赖注入Application!
  @Override
  public void injectMembers(MyApplication instance) {
    instance.dispatchingAndroidInjector = dispatchingAndroidInjectorProvider.get();
  }
}

大家可以明白了,原来第四步初始化该对象时,会将传入的dispatchingAndroidInjectorProvider存储起来,将来用到的时候将其对象注入到需要注入的Application中:

public class MyApplication extends Application implements HasActivityInjector {
    //就是注入给这个成员变量!
    @Inject
    DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;
    //省略其他代码
    ...
    ...
}

整理思路

现在我们再来看一下这张图,相信您已经对这张图有所领会了。

这里写图片描述

可以看到,Application进行初始化时,仅仅一部DaggerMyAppComponent.create(),就已经处理了如此多的事件,初始化了这么多工厂类,等待我们去调用他们实现依赖注入了。

二、DaggerMyAppComponent.create().inject(this)原理

其实这个步骤就是确定一下我们上面的对Dagger-Android这个库的分析是否是对的,我们来看这行代码

public final class DaggerMyAppComponent implements MyAppComponent {
    ...
    ...
    ...
    
    @Override
    public void inject(MyApplication application) {
        myApplicationMembersInjector.injectMembers(application);
    }
}

这就和我们上面第四步的分析吻合了:

//我们刚才分析过的,再看一遍
//核心代码
public final class MyApplication_MembersInjector implements MembersInjector<MyApplication> {
  private final Provider<DispatchingAndroidInjector<Activity>> dispatchingAndroidInjectorProvider;
  ...
  ...
  ...
  //依赖注入Application!
  @Override
  public void injectMembers(MyApplication instance) {
    instance.dispatchingAndroidInjector = dispatchingAndroidInjectorProvider.get();
  }
}

public class MyApplication extends Application implements HasActivityInjector {
    //就是注入给这个成员变量!
    @Inject
    DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;
    //省略其他代码
    ...
    ...
}

整理思路

这里写图片描述

可以看到,这一步实际上我们做了至关重要的一步,就是把Application中的这个不知道是干什么的成员变量进行了初始化!!!

@Inject
DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;

我们现在知道,这个dispatchingAndroidInjector中,实际拥有一个Map,Map中有着所有Activity所需依赖注入使用的Component!

可以说,这个看起来平凡无奇的成员变量,才是我们整个项目依赖注入的大管家!

顿悟

相信如果您认真一步步看到这里,对于下面的2个问题,您已经有了自己的答案:

  • 1.MyApplication中的dispatchingAndroidInjector成员是干嘛的

三、 AndroidInjection.inject(this)原理

我们在初始化一个Activity,必然会调用BaseActivity中的这行代码:

AndroidInjection.inject(this)

我们好奇,为什么仅仅在BaseActivity这样1行依赖注入代码,就能代替之前我们每个Activity都需要写的模板代码呢?

答案近在眼前。

public final class AndroidInjection {
  ...
  ...
  ...
  public static void inject(Activity activity) {
    //核心代码如下
    //1.获取Application
    Application application = activity.getApplication();
    
    //2.通过activityInjector()获取dispatchingAndroidInjector对象!
    AndroidInjector<Activity> activityInjector =
        ((HasActivityInjector) application).activityInjector();
        
    //3.dispatchingAndroidInjector依赖注入
    activityInjector.inject(activity);
  }
}

前两步毫无技术含量,我们继续看activityInjector.inject(activity):

我们需要找到真正的activityInjector对象,就是DispatchingAndroidInjector:

public final class DispatchingAndroidInjector<T> implements AndroidInjector<T> {

  @Override
  public void inject(T instance) {  //instance在这里为Activity
    //1.执行maybeInject()方法
    boolean wasInjected = maybeInject(instance);
  }
  
  public boolean maybeInject(T instance) {  //instance在这里为Activity
    //2.获取对应Provider
    Provider<AndroidInjector.Factory<? extends T>> factoryProvider =
        injectorFactories.get(instance.getClass());
    
    AndroidInjector.Factory<T> factory = (AndroidInjector.Factory<T>) factoryProvider.get();
     
     //3.获取对应的ActivityMembersInjector
     AndroidInjector<T> injector =
              factory.getClass().getCanonicalName());
      //4.注入到对应的Activity中
      injector.inject(instance);
  }
}

整理思路

可以看到,这一步实际上我们只是取得Application中的大管家dispatchingAndroidInjector,通过它取得了对应Activity的Inject实例,并进行依赖注入。

顿悟

相信如果您认真一步步看到这里,对于下面的2个问题,您已经有了自己的答案:

  • 2.MyApplication实现的HasActivityInjector接口和实现的activityInjector()方法又是干嘛的
  • 3.为什么这样2行依赖注入代码,就能代替之前我们每个Activity都需要写的模板代码呢:

至此,AndroidInject原理分析基本也到了尾声

附录

最后提供一下本文demo源码连接和图片资源,都已放到Github:

https://github.com/qingmei2/Sample_dagger2

本文所使用的高清图片链接

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,326评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,228评论 1 304
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,979评论 0 252
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,489评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,894评论 3 294
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,900评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,075评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,803评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,565评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,778评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,255评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,582评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,254评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,151评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,952评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,035评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,839评论 2 277

推荐阅读更多精彩内容