Dagger2一步步实现MVP

前言

Dagger2是dagger的升级版,dagger是由square公司开发,github链接:https://github.com/square/dagger,不过,它的升级版dagger2,现在由Google接手维护,github链接:https://github.com/google/dagger。
dagger2到底做什么用?简单地说:依赖注入。
在软件工程领域,依赖注入(Dependency Injection)是用于实现控制反转(Inversion of Control)的最常见的方式之一。

为什么需要依赖注入

控制反转用于解耦。
举个栗子

public class A{
  ...
  Class b;
  public A(){
      b=new B();
    }

public void doSomething(){
      b.do();
  }
  ...
}

上面的写法我们经常用到,也都是这么写的,那么这么写有什么问题吗?试想一下,如果Class B发生变化了,比如构造方法需要参数,或者do()方法需要传参数,那么我们就不得不改Class A的构造方法,所有用到A实例的地方就都需要修改了。这样,AB就仅仅耦合在一起了,对以后程序的扩展修改不利。开闭原则告诉我们程序应该是对外扩展开放,对修改关闭,这正好与这一原则相违背。

依赖注入的实现方式

我们的代码中有很多依赖注入,只不过我们没有察觉罢了。依赖注入主要有以下集中方法:

  • 构造函数注入
public class ClassH {

  ClassB classB;
  
  public ClassH(ClassB b){
    this.classB=b;
  }
}
  • setter方法注入
  public class ClassH {

  ClassB classB;
  
  public void setClassB(ClassB b){
    this.classB=b;
  }
}
  • 通过接口注入
interface IClassH(){
  void setB();
}

public class ClassH implement IClassH{

ClassB classB;

   @override
      void setB(ClassB b) {
          classB = b;
      }
}

最后,是通过Dagger2的方式注入。下面是通过http://www.jianshu.com/p/8527e3bb9097,MVP模式的登录栗子,用一下Dagger2。

Dagger2的引入
dependencies {
  compile 'com.google.dagger:dagger-android:2.x'
  compile 'com.google.dagger:dagger-android-support:2.x' // if you use the support libraries
  annotationProcessor 'com.google.dagger:dagger-android-processor:2.x'
annotationProcessor 'com.google.dagger:dagger-compiler:2.12'
}

对于Android Studio版本在2.2以下的,用以下的方法引入Dagger2。

  • 配置apt插件,在Project的build.gradle下
dependencies {
        classpath 'com.android.tools.build:gradle:2.3.1'
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
  • 添加依赖,在Module下的build.gradle下
apply plugin: 'com.android.application'
  //添加如下代码,应用apt插件
  apply plugin: 'com.neenbedankt.android-apt'
  ...
  dependencies {
      ...
      compile 'com.google.dagger:dagger:2.4'
      apt 'com.google.dagger:dagger-compiler:2.4'
      //java注解
      compile 'org.glassfish:javax.annotation:10.0-b28'
      ...
  }

Dagger2的使用

具体使用可以参照:https://google.github.io/dagger/android.html,Google的Dagger2官方支持,分Activity和Fragment的inject。
Dagger是基于MVP模式的,不了解MVP模式的请先移步 http://www.jianshu.com/p/8527e3bb9097,这是一个基于MVP模式的登录模块。

下面参考前面的mvp登录模块,一步步使用Dagger2。
以在LoginActivity中注入LoginPresenter为例,大致可以分为5步。

1 在LoginActivity中Inject目标类。

这里我们在LoginActivity中注入了LoginPresenter 的对象。mLoginPresenter,这样就可以不通过new的方式创建实例,达到了解耦的目的。

   @Inject
   LoginPresenter mLoginPresenter;

这里遇到了第一个注解符@Inject。

注解符

  • @Inject:在需要注入依赖的地方使用这个注解,你用它告诉Dagger这个 构造方法,成员变量或者函数方法需要依赖注入。这样,Dagger就会构造一个这个类的实例并满足他们的依赖。

注入之后,LoginActivity节持有了LoginPresenter的实例mLoginPresenter,如果这时候你运行一下代码,会报错,NullPointerException,为什么呢?原因是虽然我们Inject了mLoginPresenter,但是我们并没有真正实例化她,那么它在哪实例化呢?在Module里

2 编写Module,为注入时的实例化提供参数

先上代码

@Module
public class LoginModule {

    private IView.ILoginView loginView;

    public  LoginModule(IView.ILoginView view){
        this.loginView=view;
    }

    /**
     * 提供LoginPresenter
     * @param iLoginView
     * @return
     */
    @Provides
    @Singleton
    LoginPresenter provideLoginPresenter(IView.ILoginView iLoginView){
        return new LoginPresenter(iLoginView);
    }

    @Provides
    @Singleton
    IView.ILoginView provideILoginView(){
        return loginView;
    }
    
}

说明

  • Module的作用是用来提供生成依赖对象的,生成实例的,你可以把它看成是一个工厂,里面生产各种各样的实例。
  • 必须要用@Module注解,说明此类是个Module

注解符

  • @Module 用Module标注的类是专门用来提供所有依赖的,里面有几个provideXXX()方法就提供多少个依赖
  • @Provides 在Module中,我们定义的方法是用这个注解,以此来告诉Dagger我们想要构造对象并提供这些依赖。也就是说,@Provides用在方法上,是提供具体依赖的。
  • @Singleton 当前提供的对象将是单例模式 ,一般配合@Provides一起出现

至此我们的实例化过程完成了,下面还有一点要补充说明的

补充
是不是只能用Module提供以来对象呢,不是的,以我们的上面的例子说明,LoginActivity里注入了LoginPresenter对象,如果我们不编写Module,那怎么生成实例呢。

@Inject
   LoginPresenter mLoginPresenter;

答案是到LoginPresenter的构造方法前,加上@Inject注解。如下代码所示

@Inject
    public LoginPresenter(IView.ILoginView iLoginView) {
        this.mILoginView = iLoginView;
        mLoginModel = new LoginModel();
    }

这样也可以完成实例化过程。
也许你要问,既然这样可以完成实例化,为么还要编写Module呢?
答案是:

  • 如果项目中使用到了第三方的类库,第三方类库又不能修改,所以根本不可能把Inject注解加入这些类中,这时我们的Inject就失效了。
  • 如果我们以这种方法提供实例化,那么实例化过程会分散在整个项目中,而Module正好可以将它们集中起来管理。

整个注入,实例化的过程可以用下面的步骤描述:

当遇到@Inject注解时:

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

现在实例已经构建好了,现在我们有了(1)依赖的使用方:LoginActivity,通过 @Inject注入(2)依赖的提供方Module。
怎么才能在两者之间建立桥梁呢,答案是Component

3 编写Component

Component一般用来标注接口,如上文所说,作用在于作为依赖提供方和依赖使用方沟通的桥梁。

@Singleton
@Component(modules = {LoginModule.class})
public interface LoginComponent {

    void inject(LoginActivity loginActivity);

}
  • 一个类要想是Component,必须用Component注解,并且该类是接口或抽象类,并通过(modules = xxx.class)绑定对应module,并声明一个inject方法,在依赖的使用方会用到
  • @Inject和@Module的桥梁,它的主要作用就是连接这两个部分
  • 我们要列出所有的@Modules组成该组件,如果缺失了任何一块都会在编译的时候报错
4 编译。AndroidStudio -> Build -> Make Project

编译后,MainComponent生成一个DaggerXXXComponent类,这个类我们最后一步用到。

5 在Activity中注入
 DaggerLoginComponent.builder()
                .loginModule(new LoginModule(this))
                .build()
                .inject(this);

效果是一样的


Dagger2一步步实现MVP_第1张图片

代码下载:https://github.com/baojie0327/SsrjMvp

你可能感兴趣的:(Dagger2一步步实现MVP)