个人博客:haichenyi.com。感谢关注
众所周知,dagger的入门是比较难的,在嵌入之前,我先说一下这个dagger必要的东西,也是比较常见的东西,几个注解 @Component,@Singleton,@Module,@Provides,@Inject
大致的整个流程如下:
- 编译的时候,先找构造方法由@Inject标记的类,生成对应的Factory.class类,这个类里面通过new生成对应的对象
- 然后,moudle里面,每一个由@Provider标记的方法,都会生成一个对应的Factory.class文件,这里返回的对象,就是刚才由new生成的对象
- 最后,我们通过component获取对象的时候,就找moudle去取。moudle取的对象就是之前new生成的
也可以这样理解:
- @Component直到桥梁的作用,告诉application,activity我能给你提供哪些对象
- 当Component中返回对象时,它会到@Module中去找这个对象创建没
- @Module中的方法很多,它不可以每个方法的识别一次,它只找@Provider标记的方法
后文的说明都是依赖于kotlin框架
这里我拿如下方法来说明整个流程:
图一.png如上图:在AppComponent里面的getSpHelper()方法,返回对象就是SpHelper,前面我们说了,component里面需要的对象要在moudle里面找,moudle里面需要的对象要在@Inject的地方生成,所以,moudle里面也要有对应的方法:如下图:
图五.png这里的,整个SpHelper是个什么东西呢?参数SpReal又是个什么东西呢?他就是一个sharePreference的接口。SpReal是SpHelper的实现类,如下图:
图二.png这个就是一个普通的接口,与dagger2搭不上边。我们看他的实现类:
图三.png如上图:类SpReal实现SpHelper接口,并且,它的构造方法用@Inject标记了。这里就跟我们的dagger2搭上关系了,我们就需要找SpReal对应的Factory.clss文件。如下图:
图四.png如上图,SpReal_Factory类有三个方法,两个get()方法返回SpReal对象,静态的newInstance()方法也是返回SpReal对象,静态的create()方法,返回的是当前类的对象。那么,这里的调用顺序是什么呢?
我们在转过头来看看moudle里面方法对应的Factory:如下图
图六.png如上图,左边我们看到AppMoudle生成了三个对应的Factory文件,为什么会生成三个?因为,我们的AppMoudle里面有三个方法是用注解@Provides标记的,可以回过头去看一下AppMoudle的内容。
我们仔细看一下,我们需要的这个类的内容AppModule_ProvideSpHelperFactory,一共有四个方法:一个构造方法,一个get方法,一个create方法,一个provideSpHelper方法。
是不是很眼熟这个providerSpHelper方法,并且他的返回值也是SpHelper,没错,这个方法就是我们AppMoudle里面定义的方法,在这里生成的对应的方法,它只是参数多了一个AppModule,为什么会多了这个参数呢?带着这个问题,我们看这个方法的实现:
图七.png可以点击跳转这个方法,你会发现,它跳转回我们的AppMoudle方法里面对应的provideSpHelper()方法。回过头来想,我们的AppMoudle就是一个类,里面的provideSpHelper()就是一个普通的方法,怎么调用这个方法呢?就只有用 对象.方法名() 调用,所以,这里参数就多加了一个AppMoudle。
上面解释了为什么多了一个参数,我们再来看一下这个方法的实现。如下图:
图八.png如上图,就是一个非空判断,如果为空就抛出空指针异常,如果不为空,就返回第一个参数。第一个参数是什么呢?第一个参数,不就是,我们上面说的对象调用方法名么?我们来看一下它这里是怎么实现的。如下图
图九.png咦,怎么又返回来了?回到AppMoudle类了,它没有给我们实现啊?我们再想想,首先这个方法,返回的是第一个参数的值,第一个参数又是一个调用我们AppMoudle里面的方法,我们AppMoudle这个方法的返回值,就是这里这个方法的返回值。我们看一下,我们方法的返回值是什么?
图十.png我们方法的返回值,不就是传进来的参数么?那我们再看看这里方法传进来的参数是什么?
图十一.png它这里的传的参数,就是这个方法的第二个参数。到这里,我们又断了,依然不知道,这个参数从哪来的。
冷静下来想一想,调用方法,参数从哪里来?我们从方法里面实现怎么看的到,我们肯定是要在调用方法的地方看。所以,我们就要找到在哪调用这个方法的。既然是写在AppComponent里面,那我们就找他的编译后生成的文件,也就是DaggerAppComponent,如下图:
图十二.png一眼看过去,这么多东西,怎么看?我又想到,这个DaggerAppComponent类是由AppComponent生成的类,通过上面的判断,这个类里面也应该有我在AppComponent定义的方法的实现才对,搜一下getSpHelper方法,果不其然。如下图:
图十三.png如上图,我们可以看到这个方法的实现,类点方法名,说明整个方法是静态的,我们点过去一看。如下图:
图十四.png不就是,我们前面说的那个静态方法吗?这样就跟我们前面分析的都串起来了。我们前面的问题是什么?不就是不知道这个方法的第二个参数从哪来的吗?现在,我们看到了,就是在这里new出来的。
至于第一个参数AppMoudle从哪来的?我们可以接着分析一下。如下图
图十五.png我们可以看到这个appMoudle定义的是一个全局的变量,我们就要找,在哪里初始化的?如下图:
图十六.png我们发现它是在构造方法里面初始化的,我们就要找在哪里调用的这个构造方法。如下图
图十七.png我们发现,在这个Builder类里面的build()方法调用的这个构造方法,我们就找在哪里调用的这个build()方法。如下图:
图十八.png我们发现,是AndroidInjector这个接口里面的抽象Builder类,这个抽象Builder类实现的是AndroidInjector.Factory,我们要找的就是这个create()方法。
图十九.png所以,这里在我们的Application里面初始化的,也就是我这里的MyApp里面初始化的。这个参数怎么传递的?如下图:
图二十.png在create方法里面调用build()之前还调用了seedInstance()方法,这里是抽象类的方法,要想知道这个方法是怎么实现的,那就得看他的实现类。这个Builder<T>的实现类是谁?想一想上面是怎么跳转过来的?不想这个,我们也可以点这个类进行跳转。如下图
图二十一.png如上图,我们可以看到有两个地方调用,一个是ActComponent,一个是AppComponent,前面一个是activity相关的,我们还没有说到,我们现在一直说的都是Application相关的。所以,这里跳转的地方,肯定是Application。如下图
图二十二.png这个方法还过时了,正好,我们这个Builder<T>抽象类还用@Deprecated标记了。诶?那这里还是没有实现啊,这也是一个抽象类。这个是抽象类,AppComponent又是一个接口,所以,我们要找这个AppComponent接口的实现类。如下图:
图二十三.png如上图,AppComponent的实现类,就是DaggerAppComponent类。我们在这个类里面找Builder<T>的实现类就可以了。找找找,如下图
图二十四.png如上图,这里有seedInstance方法和build两个方法,而且都是@Override的,从父类继承过来的,我们在看看AndroidInjector类。如下图:
图二十五.png正好,它有这两个方法,并且还都是抽象方法。所以,这个类就是它的实现类。所以,调用的seedInstance方法,就是这里的这个方法。如下图:
图二十六.png这个方法就是做了一个赋值操作,赋值之前做了一个非空检验。所以,在执行build()的时候这个seedInstance对象已经赋值了,不是空。所以这里就走通了。如下图
图二十七.png如上的构造方法就走通了,那么appMoudle就有值了,那么我们前面的问题。如下图:
图二十八.png我们之前就是在这里,不知道这个appMoudle是怎么赋值的,这里已经走通了。这就是通过AppComponent过去getSpHelper()的整个流程了
网友评论