Dagger2使用解析

xiaoxiao2021-02-28  16

今日科技快讯

近日谷歌母公司Alphabet股价大幅上涨。公司股价收盘上涨近2%,盘中一度涨逾2.5%,至每股828.81美元,创下谷歌在2004年8月上市以来的最高纪录。相关人士分析,Alphabet公司股价大涨,主要得益于本月初推出的Pixel系列新款手机广受好评。Pixel 最大杀手锏是可以令 iPhone 用户轻松将数据转换到谷歌手机的安卓系统中,并且在拍照效果上要好于iPhone 7。

作者简介

本篇来自 study_zhxu 的第二篇投稿,之前他已经给大家分析过MVP模式,今天他将分享如何使用Dagger2,并给出自己的理解。最后祝大家周末愉快!

study_zhxu 的博客地址:

http://blog.csdn.net/study_zhxu

前言

现在 Dagger2 在项目中的使用越来越多,Dagger2 是 Dagger 的升级版本,Dagger 没有使用过,但是本篇说的是 Dagger2,主要讲解的是 Dagger2 是如何使用的。对了,忘了说 Dagger 其实是一个 依赖注入 的框架。

依赖注入

依赖注入 是一种 面向对象 的编程模式,它的出现是为了 降低耦合性,所谓 耦合 就是 类之间依赖关系,所谓降低耦合就是降低类和类之间依赖关系。

可能有的人说自己之前并没有使用过依赖注入,其实真的没有使用过吗?当我们在 一个类的构造函数中通过参数引入另一个类的对象,或者 通过set方法设置一个类的对象 其实就是使用的依赖注入。

常见依赖注入方式多

通过接口注入

通过set方法注入

public class ClassA {    ClassB classB;      public void setClassB(ClassB b) {        classB = b;    } }

通过构造方法注入

public class ClassA {    ClassB classB;        public void ClassA(ClassB b) {        classB = b;    } }

通过注解的方式注入

public class ClassA {    //此时并不会完成注入,    //还需要依赖注入框架的支持,如Dagger2    @inject    ClassB classB;    public ClassA() {} }

下面我们就来说说如何通过 Dagger2 来实现 依赖注入 吧。

引入Dagger2

添加apt插件

添加依赖(在build.gradle中添加如下代码)

使用Dagger2

添加完 Dagger 的依赖后我们如何在项目中使用 Dagger 呢?

在项目中绝大多数的使用都是 Dagger 结合 MVP架构 使用的,在 MVP 中使用是非常典型的降低耦合的使用。

本篇文章中的示例是一个简单的登陆功能的示例,该示例采用 MVP架构 设计通过 Dagger2 进行解耦合,下面就来看看如何使用吧。

在使用 Dagger2 前我们最好简单的了解一下MVP,主要是为了理解本篇中的代码。简单了解 MVP 即使不会写 MVP 也可以看的懂本篇的代码。

为什么要选择在 MVP模式 中使用 Dagger2 呢?因为在 MVP模式 中 Activity 持有 presenter 的引用,同时 presenter 也持有 view 的引用,这样便于更新UI界面,这样 Activity 就和 presenter 仅仅的耦合在一起了,而 Dagger2 是依赖注入框架就是解耦合的,所以 MVP 中使用 Dagger2 也就再好不过了。

我们看如下代码:

在上述代码中可以看到 activity 持有了presenter 的引用并且创建了该对象,但是如果 presenter 的构造函数发生改变则这里也需要改变,其实所有和 presenter 构造函数相关的代码都要改变。

但是如果我们使用 Dagger2 依赖框架该如何使用呢?请看下面代码:

activity 中的代码:

LoginPresenterCompl 中的代码:

只有上述两个注解还无法完成依赖注入,还需要如下两个新增类:

新增的 MainModule 类:

@Modulepublic class MainModule {    private final ILoginView view;    public MainModule(ILoginView view){        this.view = view ;    }    @Provides    ILoginView provideILogView(){        return view ;    } }

新增的 MainComponent 接口:

@Component(modules = MainModule.class)public interface MainComponent {    public void inject(LoginActivity activity) ; }

通过 直接注解 和 上述两个接口类 即可完成 Dagger2 的依赖注入。

在 LoginActivity 中是通过:

DaggerMainComponent.builder().mainModule(new MainModule(this)).build().inject(this)

完成依赖注入的。

看完上面的代码后,一脸的懵逼,WTF(what the fuck),这TM是什么,这么复杂,还不如之前的简单呢,新增了两个类还有这么多代码,得不偿失呀!

同志们,如果你们第一眼看到后是这样想的话,说明和我想的一样,呵呵。每一个刚接触 Dagger2 的人可能都会这样想,因为我们只看到了表面。

不错,表面上我们是多了一个类和接口也多了很多代码,但是这样的组合其实是可以理解的。因为通常简单的代码具有耦合性,而要想降低这样的耦合就需要其他的辅助代码,其实少代码量和低耦合这两者并不能同时兼顾,古人云:鱼和熊掌不可兼得。我们作为堂堂聪明绝顶的程序猿怎么可能会输给古人呢。

好!下面来认真讲解 Dagger2 是如何完成依赖注入的。

首先我们来看看 LoginActivity 代码,LoginActivity 中有这么一段代码:

@InjectLoginPresenterCompl loginPresenter;

同样在 LoginPresenterCompl 中也有这么一段代码:

@Injectpublic LoginPresenterCompl(ILoginView view){    loginView = view ;    user = new User("张三","123456") ; }

之所以挑出这两段代码是因为它们都添加了 @Inject注解。

在 LoginActivity 中其实只有这么一句提到 loginPresenter,在接下来的代码中并没有对其进行初始化。

那 loginPresenter 是如何进行初始化的呢(此处注意添加 @Inject注解 的变量不能被 private 修饰)?

直观上我们可以这样理解,被 @Inject 注解的代码存在某种联系,当代码执行到 @Inject 的时候程序会自动进入到这个类的构造方法中,如果正巧这个构造方法也被 @Inject 修饰了,那么系统就会帮我们自动创建对象。

这只是表面的理解,这其中肯定还有很多我们没有看到的“猫腻”。这俩不会无缘无故的有联系,肯定还有第三者,通过这个第三者这两个被 @Inject 注解修饰的代码才会产生联系。

这个第三者是谁呢?自然的我们就会想到我们添加的这个 类 和 接口。

首先我们来分析 MainComponent 接口,代码如下:

@Component(modules = MainModule.class)public interface MainComponent {    public void inject(LoginActivity activity) ; }

MainComponent 是一个接口(也可以是一个抽象类),在这个接口中我们定义了一个 inject() 方法,其中参数是 LoginActivity对象,同时 MainComponent 还被 @Component 注解着,注解中 modules 的值是 MainModule.class,这个内容会在接下来的地方进行说明,暂时先放一放。

此时在 Android Studio 中,如果我们 rebuild 的一下项目就会有新的发现。在项目的 build/generated/source/apt/debug/项目包名/dragger 目录下生成对应的包其中包含 DaggerMainComponent 类,这个类名其实不是固定的,是根据我们上面写的 MainComponent,加了 Dagger 前缀生成的 DaggerMainComponent。其实在这个时候我们就已经完成了 present 的依赖注入。

但是在:

DaggerMainComponent.builder().mainModule(new MainModule(this)).build().inject(this)

中我们看到还有一个 MainModule,这个是我们自己创建的一个类,MainModule 代码如下:

@Modulepublic class MainModule {    private final ILoginView view;    public MainModule(ILoginView view){        this.view = view ;    }    @Provides    ILoginView provideILogView(){        return view ;    } }

我们可以看到这个类被 @Module 注解修饰,内部有一个 ILoginView 的变量和一个构造方法还有一个被 @Provides 修饰的 provideILogView 方法。

看到这还是一脸懵逼,这个类是干嘛的?

在 MainComponent 接口中我们看到这么一个注解 @Component(modules = MainModule.class),这里用到了 MainModule,可见 MainComponent 需要 MainModule 一起才能完成工作。

其实这个类我们可以理解成提供参数的,也就是提供参数依赖的,如何理解呢?

在 MainModule 中我们为什么要提供 ILoginView 类型的对象?为什么不是其他的呢? 

这是因为 LoginPresenterCompl 的构造函数需要这么一个参数,所以我们在这里提供这么一个相同的参数,并通过被 @Provides 注解修饰的方法将其返回出去,如果 LoginPresenterCompl 还需要其他的参数,同样我们也可以在这里添加对应类型的参数然后通过另一个被 @Provides 注解修饰的方法返回出去。

在 MainComponent 接口中提供的 inject() 方法的参数是 LoginActivity,这个参数的含义是 LoginPresenter 要在什么地方注入。

了解了各个类的功能后我们来总结一下:

@Inject 程序会将 Dagger2 会将带有此注解的变量或者构造方法参与到依赖注入当中,Dagger2 会实例化这个对象。

@Module 带有该注解的类需要对外提供依赖,其实就是提供实例化需要的参数,Dagger2 在实例化的过程中发现一些参数,Dagger2 就会到该类中寻找带有@Provides 注解的以 provide 开头的需找对应的参数。

@Component 带有该注解的接口或抽象类起到一个关联桥梁的作用,作用就是将带有 @Inject 的方法或对象和带有 @Module 的类进行关联,只有通过该接口或抽象类才可以在实例化的时候到带有 @Module 中类中去寻找需要的参数,也就是依赖注入。

OK,下面我们来捋捋思路。

1. 在这个示例代码中,LoginActivity 中需要 LoginPresenterCompl,所以在 LoginActivity 中定义了该对象并且通过 @Inject 将其注解,同时到 LoginPresenterCompl 的构造方法中也通过 @Inject 将其注解, 表明这些是需要依赖注入的。

2. 因为在 LoginPresenterCompl 的构造方法需要 ILoginView 类型的参数,所以需要通过依赖将获取这些参数,所以就需要带有 @Module 注解的类用于获取需要的参数,在 @Module 注解的类中通过被 @Provides 注解的以 provide 开头的方法对外提供需要的参数,一般而言有几个参数就需要有几个带有 @Provides 的方法。

3. 此时还需要一个桥梁将两者联系到一起,带有 @Component 的接口或抽象类就起到这个桥梁的作用。注解中有一个 module 的值,这个值指向需要依赖的 Module 类,同时其中有一个抽象方法  inject(),其中的参数就是我们需要在哪个类中实例化 LoginPreserentCompl,因为我们需要在 LoginActivity 中实例化,所以参数类型就是LoginActivity 类型。

然后在 Android studio 中 rebuild 我们的项目,就会生成 DaggerMainComponent 类,通过:

DaggerMainComponent.builder().mainModule(new MainModule(this)).build().inject(this);

完成我们需要的依赖注入。

更多

如果你有好的技术文章想和大家分享,欢迎向我的公众号投稿,投稿具体细节请在公众号主页点击“投稿”菜单查看。

欢迎长按下图 -> 识别图中二维码或者扫一扫关注我的公众号:

转载请注明原文地址: https://www.6miu.com/read-1250118.html

最新回复(0)