MVP + Dagger2源码体验
大家好,我是苍王。
以下是我这个系列的相关文章,有兴趣可以参考一下,可以给个喜欢或者关注我的文章。
[Android]如何做一个崩溃率少于千分之三噶应用app--章节列表
相信有关注我的人,都会看过我第一编介绍的Todo-mvp源码体验,这是基础编。
这一章理解难度将会非常大。
这个系列的课程适合研发有Android有一年半左右的同学参考。
基于工作的问题,大型公司其实都不怎么使用这种注入框架,而是直接用代码完成解耦的。但是学习期框架架构,对我们了解注解的使用和构建学习一些设计模式有着重要的作用。Dagger的设计的确非常精妙。
一.基础介绍
估计很多新手看Dagger2都会看到一头雾水,因为Dagger2使用的依赖反转的设计模式原则。
举个例子,我去买东西,告诉老板我需要什么品类的东西,老板就说你等着,我拿给你就好了。
这个部分都是老板帮我们完成了。
推荐一个非常好的Dagger2的入门文章给大家,里面都是Dagger2基本的使用原理,和一般的架构设计,看完之后估计大家应该不会再一头雾水。
Google官方MVP+Dagger2架构详解【从零开始搭建android框架系列(6)】
如果没有Dagger基础,而且不看介绍,然后直接看一下的内容,估计你会一头雾水。(最好下源码对着看)
没Dagger基础一定要看介绍
没Dagger基础一定要看介绍
没Dagger基础一定要看介绍
重要的事情说三次!!!
二.源码分析
(一).引用相关
关于引用,需要使用android-apt的引用
![](https://img.haomeiwen.com/i692087/c4e79614b7af7c8e.png)
还有Dagger2所需要的依赖
![](https://img.haomeiwen.com/i692087/b485cc8737bcdec8.png)
一开始下载下来,打开XXActivity的文件发现都会报红,然后需要我们make projects一次,Dagger2会自动生成一些Dagger注入的类。
![](https://img.haomeiwen.com/i692087/13e08b736c0acb93.png)
编译完成后,我们会在apt的文件夹里面,看到生成的Dagger代码,很显然是通过apt代码编写的代码。
这里的套路和MVVM有点相似,但是MVVM是源码就提供MVVM的自动编码,而Dagger2需要apt去做。
![](https://img.haomeiwen.com/i692087/eeab30c9f394e9f7.png)
(二).Application注解
我们看自定义的ToDoApplication,可以简单到看到mRepositoryComponnet是数据源在这里声明为全局的变量
![](https://img.haomeiwen.com/i692087/7915b54ab6af3df3.png)
这里会引用到自定义的ApplicationModule实体类,外面的变量通过provideContext获取ApplicationContext参数。
![](https://img.haomeiwen.com/i692087/6904b3f5bd7f0ccf.png)
(三).Component注解
我们这里先以TaskDetailActivity为例吧(这里不对Dagger2的注入方式再进行介绍,可以看我基础介绍里面的网址学习)
我们看到DaggerTaskDetailComponent是使用了建造者模式的链式结构。
![](https://img.haomeiwen.com/i692087/e5ca161af0b0c7b1.png)
我们看到的是自动生成的DaggerTaskDetailComponent是继承TaskDetailComponent
我们看到起使用@Provider就会生成Provider类型的变量
使用@Inject标志的变量就会被声明为MembersInjector的变量
因为使用了inject(this)还会将整个TaskDetailActivity声明为MembersInjector的变量
![](https://img.haomeiwen.com/i692087/4d9789f6170387fe.png)
看到这里应该很清楚,起初始化的时候,还会调用intialize方法
![](https://img.haomeiwen.com/i692087/76192faceed132b7.png)
这里很明显,每个变量都会通过XXXFactory.create来获取相应的创建出来(这里使用很明显就是工厂模式)
Module声明的实体主要是用到了工厂模式生成
![](https://img.haomeiwen.com/i692087/5292f1734cd0c009.png)
使用inject(this)的时候会调用injectMembers的方法替换变量
![](https://img.haomeiwen.com/i692087/d531f3d971c10760.png)
深入到TaskDetailActivity_MembersInjector实现类,初始Presenter对象
![](https://img.haomeiwen.com/i692087/fe2cb73f6bb7b183.png)
这里初始化的时候会输入PresenterProvider的变量
![](https://img.haomeiwen.com/i692087/39d5a6a8d8a9552f.png)
其是通过静态的create方法做成工厂的。
![](https://img.haomeiwen.com/i692087/35cdf5337775ea2b.png)
这里是DaggerTaskDetailComponent的intialize的时候会加载Provider
![](https://img.haomeiwen.com/i692087/53e03457458104ea.png)
继续是工厂类创建
![](https://img.haomeiwen.com/i692087/f3d7b92eb78e35b2.png)
其会创建出一个工厂类的方法出来。
![](https://img.haomeiwen.com/i692087/b503c51b65bfba3e.png)
这里继续下来是很酷的是建造者模式Buidler。
可以看出Component的核心源码系建造者模式。
![](https://img.haomeiwen.com/i692087/50b7a6df8896c30f.png)
这里需要确立的是build一定是在inject之前的,先输入参数建造才能注入。
![](https://img.haomeiwen.com/i692087/bf0613bb6c8ac7d3.png)
Presenter是什么时候被初始化的呢?
我们看到TaskActivity里面注入Presenter
![](https://img.haomeiwen.com/i692087/341ea0b17b2ac7b0.png)
获取taskPresenterModule的对象
![](https://img.haomeiwen.com/i692087/bb03bbf428287069.png)
TaskPresenter里面构造
![](https://img.haomeiwen.com/i692087/f02f491a47d80cea.png)
(1)关于tasksPresenterMembersInjector的获取
![](https://img.haomeiwen.com/i692087/d77a3a3e31040e09.png)
我们看到这里初始化
![](https://img.haomeiwen.com/i692087/09cf862589bb3722.png)
然后在TaskPresenter_Factory通过get方法来获取
![](https://img.haomeiwen.com/i692087/42c8c6e27ed95d1e.png)
这里还涉及到一个Listeners的方法
![](https://img.haomeiwen.com/i692087/2c0cb620f7eb47d6.png)
其实现是在TasksPresenter里面
![](https://img.haomeiwen.com/i692087/29beb201e8155abf.png)
(2)关于TaskDetailPresenter
TaskDetailPresenter的获取是在TaskDetailActivity
这里provideTaskIdProvider其引用是provideTaskId
provideTaskDetailContractViewProvider对应的是provideTaskDetailContractView
![](https://img.haomeiwen.com/i692087/4766a3b59892c49a.png)
这里声明了FragmentScoped的定义域(Scope其定义是单例的定义域)
还有dependencies就是TaskRepositoryComponet的数据源来源
![](https://img.haomeiwen.com/i692087/4d90c9842ce6d637.png)
其getTasksRepositoryProvider 其提供者应该是getTasksRepository.
![](https://img.haomeiwen.com/i692087/ea37f8c1315bd9aa.png)
其实体对象获取方式,是通过初始化的时候传入TasksRepositoryComponent的实体
![](https://img.haomeiwen.com/i692087/77a20e778d5d67f7.png)
传入数据提供实体
![](https://img.haomeiwen.com/i692087/d6586001117555d4.png)
在自定义的Application中建立数据实体
![](https://img.haomeiwen.com/i692087/95963f04645671ec.png)
(四).关于数据实体TasksRepository
我们分为近端和远端数据
这里@Qualifer是自定义命名的注解
![](https://img.haomeiwen.com/i692087/74d337d075f2565f.png)
![](https://img.haomeiwen.com/i692087/4975fe7863d810f6.png)
@声明数据单例
![](https://img.haomeiwen.com/i692087/ed3971f64be6e478.png)
初始化中带有本地和远端的注解对象
![](https://img.haomeiwen.com/i692087/1d2860090d6bb45c.png)
![](https://img.haomeiwen.com/i692087/7e643d04a1e87792.png)
![](https://img.haomeiwen.com/i692087/70d8ed9be57a75e1.png)
在DaggerTasksRepositoryComponent中联通这些注解对象
![](https://img.haomeiwen.com/i692087/e849dae7da37cc63.png)
通过getTasksRepository获取到实体到数据流实体
![](https://img.haomeiwen.com/i692087/524b848a13da9f53.png)
![](https://img.haomeiwen.com/i692087/ab3e91e4db2459ef.png)
设定通过单例@Singleton的方法获取远端和近端的数据
![](https://img.haomeiwen.com/i692087/a22e15c1121b673d.png)
其单例的声明是通过enum枚举,然后声明INSTANCE的方式,声明单例的。
![](https://img.haomeiwen.com/i692087/858f1981c75dea12.png)
这里特别说名一下一个没有scope的组件component不可以依赖一个有scope的组件component。子组件和父组件的scope不能相同。我们通常的ApplicationComponent都会使用Singleton注解(),也就会是说我们如果自定义component必须有自己的scope。
![](https://img.haomeiwen.com/i692087/6b9311cc74c1b021.png)
三.总结
Dagger2注解,框架最重要理解的就是依赖倒置的设计原则。
Dagger2源码的套路
Module->Factory.create 工厂创建
Component-> XXXComponent.Bulider 建造者模式
Singleton Scoped-> 利用enum和INSTANCE标示 单例模式
理解这些设计模式,一旦你真的看懂Dagger2的设计模式,你会觉得Dagger2的设计非常精妙。可以理解其Apt的注解编写的设计真的非常值得学习,以后有机会会给大家分享Apt编写代码的一些详解。
这次的源码分析就到这里
下一节应该会分析MVP +RXJava的源码,敬请期待!!!
我建立了一个关于Android架构学习的群,里面可以进一步进行组件化学习和架构思想的的交流。
群号是316556016,也可以扫码进群。我在这里期待你们的加入!!!
![](https://img.haomeiwen.com/i692087/13907eb28a45700c.png)