关于MVP+Dagger2的一些知识

140 阅读7分钟

原文地址:www.jianshu.com/p/01d3c014b…

看了大神Android-从零开始搭建android框架系列 前几章还比较清晰 到了dagger2发现了dagger2的优点 但是+mvp就不是特别理解如何在项目中运用。

文章评论中推荐了另一个作者的文章

地址 :www.jianshu.com/p/65737ac39…

需要找时间把这三篇文章看明白 然后再修改mvp模式的demo

笔记1. 依赖注入(Dependency Injection简称DI) java中 注解(Annotation)

Inject 优点:取消new对象通过 注入 获取实例 注解(Annotation)来标注目标类中所依赖的其他类,同样用注解来标注所依赖的其他类的构造函数,那注解的名字就叫Inject

Component 一个连接两个类的桥梁 需要引用到目标类的实例,查找用Inject注解标注的属性,与对应的构造函数并赋值,Component也叫注入器(Injector)

Module 封装第三方类库使用,简单的工厂模式。

Component中的modules属性可以把Module加入Component,modules可以加入多个Module。

Provides Module中的创建类实例方法用Provides进行标注,Component在搜索到目标类中用Inject注解标注的属性后,Component就会去Module中去查找用Provides标注的对应的创建类实例方法,这样就可以解决第三方类库用dagger2实现依赖注入了。

笔记2

Qualifier(限定符) 通过Inject创建实体类和通过Module创建实体类创建一个类时,依赖注入迷失,用限定符对不同创建实例方法标识,对目标类响应的实例属性进行标注,能解决问题。

Scope(作用域) 通过自定义Scope注解可以更好的管理创建的类实例的生命周期。

划分Component有两种,一种针对全局,最终针对activity或者fragment

Singleton (在Module中定义创建全局类实例的方法 ApplicationComponent管理Module 保证ApplicationComponent只有一个实例) 更好的管理ApplicationComponent和Module之间的关系,保证ApplicationComponent和Module是匹配的。若ApplicationComponent和Module的Scope是不一样的,则在编译时报错。

组织Component 类实例共享三种方式 依赖方式:Component中的dependencies属性 包含方式:SubComponent就是包含方式的具体实现 继承方式:把一些Component共有的方法抽象到一个父类中,然后子Component继承

Scope 更好的管理Component之间的组织方式,更好的管理Component与Module之间的匹配关系,可读性提高,如用Singleton标注全局类,这样让程序猿立马就能明白这类是全局单例类。

笔记3

dagger2的好处 增加开发效率,省去重复的简单体力劳动。 更好的管理类实例。 解耦

步骤1:查找Module中是否存在创建该类的方法。
步骤2:若存在创建类方法,查看该方法是否存在参数
步骤2.1:若存在参数,则按从**步骤1**开始依次初始化每个参数
步骤2.2:若不存在参数,则直接初始化该类实例,一次依赖注入到此结束
步骤3:若不存在创建类方法,则查找Inject注解的构造函数,
       看构造函数是否存在参数
步骤3.1:若存在参数,则从**步骤1**开始依次初始化每个参数
步骤3.2:若不存在参数,则直接初始化该类实例,一次依赖注入到此结束

`

注意事项 1.一个app必须要有一个Component(名字可以是ApplicationComponent)用来管理app的整个全局类实例 2.多个页面可以共享一个Component 3.不是说Component就一定要对应一个或多个Module,Component也可以不包含Module 4.自定义Scope注解最好使用上,虽然不使用也是可以让项目运行起来的,但是加上好处多多。

接下来分析一下大神的Demo

原地址:github.com/niuxiaowei/…

首先看一下项目结构

结构1.png

结构2.png

这里边有个有趣的事情 App这个类中DaggerAppComponent 是报错的 没有找到这类,但是项目编译后已经导入不报错了,点开文件发现文件在debug文件夹内

结构3.png

这个文件位置在上边,这种情况我是没有用到过的,发现这个类被 @Generated 标记了,也许和这个标注有关。

Demo运行起来很简单 两个按钮 一个获取用户信息,一个点击显示toast

首先分析一下data包 GetUserData构造方法被 @Inject标注了,其中还有getUser()方法,返回的是一个UserData的实例,name属性有值。 UserData是一个实体类只有一个name属性。

di包就是dagger2用到相关的类

components包连接两个类的桥梁 ActivityComponent 是同时被Component和scopes.PerActivity标注的里边有一个getActivity()方法。 AppComponent有两个标记@Singleton是单例的意思,@Component是连接器的意思,里边有3个方法,获取上下文,获取toast工具,获取Navigator。 MainComponent有两个标记@PerActivity和@Component并继承了ActivityComponent。里边有两个方法inject(mainActivity)方法和获取mainFragmentComponent实例的方法。 MainFragmentComponent类中有两个标记@PerActivity和@Subcomponent,还有一个inject(mainFragment)方法。

modules封装第三方类库使用,简单的工厂模式。 AppModule被@Module标记,里边有个三个方法provideContext,provideNavigator,provideToastUtil都被 @Provides 和@Singleton标记。 ActivityModule也被@Module标记,在构造方法中传入了activity实例,并通过被@Provides 和 @PerActivity 标记的provideActivity方法return出去。 MainModule也被@Module标记,里边只有1个@Provides标记的provideUserData()方法

scopes作用域包只有被@Scope和@Retention标记的PerActivity接口。

presenter包下只有MainPresenter这个类,里边有一个静态接口IUserView和它的set方法与实例。它的构造方法被@Inject标记并传入了GetUserData的实例,通过getUser方法给接口传递了数据

view包下 BaseActivity 有1个getAppComponent方法,BaseFragment没有方法。 MainActivity实现了MainFragment中的一个监听接口,通过DaggerMainComponent.builder()方法获取了ActivityModule的对象并调用了inject方法,提供了getMainComponent方法 return这个对象。 mainFragment这个类中通过@Inject 获取了mainPresenter、toastUtil、multiConstruct三个实例在onActivityCreated方法中得到MainFragmentComponent对象并实现inject方法,通过mainPresenter的setUserView 设置了数据,在onCreateView的两个点击事件中通过mainPresenter获取了数据,通过toastUtil展示了toast.

在包的最外层App的onCreate中获取了AppModule对象并提供了return方法。 MultiConstruct类中 @Inject了构造函数 Navigator被@Singleton标记了。 ToastUtil封装了展示吐司的方法。

总结一下: di包的components包中都是注入器,有app注入器、activity注入器、main注入器、fragment注入器。main注入器继承了activity注入器,对MainActivity进行依赖注入。 Module是一个提供类实例的类,通过标注关联了2个实例MainModule和ActivityModule,加入main注入器,他们的方法都被@Provides标注了。 当module中的类需要创建实例的时候需要用@PerActivity标记出来。 MainComponent继承了ActivityComponent并采用dependencies标记依赖了 AppComponent。 MainFragmentComponent通过@PerActivity与MainComponent声明了相同的作用域并通过@Subcomponent声明被包含的。

工厂模式也可以降低耦合度。 依赖注入:从容器中查找合适的对象,对当前的对象进行赋值。 被@Component标注类为注入器,bean生成工厂类,运行后在apt-debug包下。 注入器不能直接new 只能通过创建器进行创建。

@Inject只能针对无参构造,可以修改源代码。

@Module与@Provides 针对有参构造和jar包使用。对工厂模式类进行@Module,对实例类@Provides 方法用Provides 开头。在component类中标注出module的类,inject方法查找界面@inject的类进行赋值。调用时需多指定创建实例的工厂。

获取注入器 需要编译 生成dagger开头的类