众所周知,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框架
这里我拿如下方法来说明整个流程:
如上图:在AppComponent里面的getSpHelper()方法,返回对象就是SpHelper,前面我们说了,component里面需要的对象要在moudle里面找,moudle里面需要的对象要在@Inject的地方生成,所以,moudle里面也要有对应的方法:如下图:
这里的,整个SpHelper是个什么东西呢?参数SpReal又是个什么东西呢?他就是一个sharePreference的接口。SpReal是SpHelper的实现类,如下图:
这个就是一个普通的接口,与dagger2搭不上边。我们看他的实现类:
如上图:类SpReal实现SpHelper接口,并且,它的构造方法用@Inject标记了。这里就跟我们的dagger2搭上关系了,我们就需要找SpReal对应的Factory.clss文件。如下图:
如上图,SpReal_Factory类有三个方法,两个get()方法返回SpReal对象,静态的newInstance()方法也是返回SpReal对象,静态的create()方法,返回的是当前类的对象。那么,这里的调用顺序是什么呢?
我们在转过头来看看moudle里面方法对应的Factory:如下图
如上图,左边我们看到AppMoudle生成了三个对应的Factory文件,为什么会生成三个?因为,我们的AppMoudle里面有三个方法是用注解@Provides标记的,可以回过头去看一下AppMoudle的内容。
我们仔细看一下,我们需要的这个类的内容AppModule_ProvideSpHelperFactory,一共有四个方法:一个构造方法,一个get方法,一个create方法,一个provideSpHelper方法。
是不是很眼熟这个providerSpHelper方法,并且他的返回值也是SpHelper,没错,这个方法就是我们AppMoudle里面定义的方法,在这里生成的对应的方法,它只是参数多了一个AppModule,为什么会多了这个参数呢?带着这个问题,我们看这个方法的实现:
可以点击跳转这个方法,你会发现,它跳转回我们的AppMoudle方法里面对应的provideSpHelper()方法。回过头来想,我们的AppMoudle就是一个类,里面的provideSpHelper()就是一个普通的方法,怎么调用这个方法呢?就只有用 对象.方法名() 调用,所以,这里参数就多加了一个AppMoudle。
上面解释了为什么多了一个参数,我们再来看一下这个方法的实现。如下图:
如上图,就是一个非空判断,如果为空就抛出空指针异常,如果不为空,就返回第一个参数。第一个参数是什么呢?第一个参数,不就是,我们上面说的对象调用方法名么?我们来看一下它这里是怎么实现的。如下图
咦,怎么又返回来了?回到AppMoudle类了,它没有给我们实现啊?我们再想想,首先这个方法,返回的是第一个参数的值,第一个参数又是一个调用我们AppMoudle里面的方法,我们AppMoudle这个方法的返回值,就是这里这个方法的返回值。我们看一下,我们方法的返回值是什么?
我们方法的返回值,不就是传进来的参数么?那我们再看看这里方法传进来的参数是什么?
它这里的传的参数,就是这个方法的第二个参数。到这里,我们又断了,依然不知道,这个参数从哪来的。
冷静下来想一想,调用方法,参数从哪里来?我们从方法里面实现怎么看的到,我们肯定是要在调用方法的地方看。所以,我们就要找到在哪调用这个方法的。既然是写在AppComponent里面,那我们就找他的编译后生成的文件,也就是DaggerAppComponent,如下图:
一眼看过去,这么多东西,怎么看?我又想到,这个DaggerAppComponent类是由AppComponent生成的类,通过上面的判断,这个类里面也应该有我在AppComponent定义的方法的实现才对,搜一下getSpHelper方法,果不其然。如下图:
如上图,我们可以看到这个方法的实现,类点方法名,说明整个方法是静态的,我们点过去一看。如下图:
不就是,我们前面说的那个静态方法吗?这样就跟我们前面分析的都串起来了。我们前面的问题是什么?不就是不知道这个方法的第二个参数从哪来的吗?现在,我们看到了,就是在这里new出来的。
至于第一个参数AppMoudle从哪来的?我们可以接着分析一下。如下图
我们可以看到这个appMoudle定义的是一个全局的变量,我们就要找,在哪里初始化的?如下图:
我们发现它是在构造方法里面初始化的,我们就要找在哪里调用的这个构造方法。如下图
我们发现,在这个Builder类里面的build()方法调用的这个构造方法,我们就找在哪里调用的这个build()方法。如下图:
我们发现,是AndroidInjector这个接口里面的抽象Builder类,这个抽象Builder类实现的是AndroidInjector.Factory,我们要找的就是这个create()方法。
所以,这里在我们的Application里面初始化的,也就是我这里的MyApp里面初始化的。这个参数怎么传递的?如下图:
在create方法里面调用build()之前还调用了seedInstance()方法,这里是抽象类的方法,要想知道这个方法是怎么实现的,那就得看他的实现类。这个Builder
如上图,我们可以看到有两个地方调用,一个是ActComponent,一个是AppComponent,前面一个是activity相关的,我们还没有说到,我们现在一直说的都是Application相关的。所以,这里跳转的地方,肯定是Application。如下图
这个方法还过时了,正好,我们这个Builder
如上图,AppComponent的实现类,就是DaggerAppComponent类。我们在这个类里面找Builder
如上图,这里有seedInstance方法和build两个方法,而且都是@Override的,从父类继承过来的,我们在看看AndroidInjector类。如下图:
正好,它有这两个方法,并且还都是抽象方法。所以,这个类就是它的实现类。所以,调用的seedInstance方法,就是这里的这个方法。如下图:
这个方法就是做了一个赋值操作,赋值之前做了一个非空检验。所以,在执行build()的时候这个seedInstance对象已经赋值了,不是空。所以这里就走通了。如下图
如上的构造方法就走通了,那么appMoudle就有值了,那么我们前面的问题。如下图:
我们之前就是在这里,不知道这个appMoudle是怎么赋值的,这里已经走通了。这就是通过AppComponent过去getSpHelper()的整个流程了