Dagger2一步步实现MVP

作者: Jackson杰 | 来源:发表于2017-11-27 17:05 被阅读0次
    前言

    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);
    

    效果是一样的


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

    相关文章

      网友评论

        本文标题:Dagger2一步步实现MVP

        本文链接:https://www.haomeiwen.com/subject/gxqfvxtx.html