Dagger2的使用

说到Dagger2,有人说他是一件神器,非常好用,但也有人觉得他学习成本太高,在项目中使用会平白的多写好多类和接口,非常繁琐,其实一开始的时候,我并没有接触过Daggers2,但是最近在做项目的时候,接触到了这件神器,我使用过后的第一个感觉,就是,"这不是Spring boot么?",不错,如果有同学使用过spring boot开发过web项目,那么在使用Dagger2的时候,肯定感觉会非常亲切了,可以说,spring boot的核心就是依赖注入,配置上几个注解之后,就可以很方便的开发web项目,他与Dagger2不同的是,spring boot是一个框架,他的注解都已经配置好了,而且针对特定功能的模块会有特定的注解,比如业务层service就可以使用@Service,控制层可以使用@Controller,而Dagger2就那么几个注解,需要我们自己去配置好,进行类之间的关联,以上,仅仅是我自己的观点,可能有误;

好吧,说了这么多,直接说使用步骤吧:

1.添加依赖:(android studio2.2以上)

    //dagger2
    compile 'com.google.dagger:dagger:2.4'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.4'

2.假定有这么一个场景:有一个艺术家,他可以唱歌,也会跳舞,那么代码可以这么写

package com.example.pengganggui.dagger2test;

/**
 * Created by pengganggui on 2018/8/27.
 * 舞蹈
 */

public class Dance {

    public Dance() {

    }

    @Override
    public String toString() {
        return "芭蕾舞";
    }
}
package com.example.pengganggui.dagger2test;

/**
 * Created by pengganggui on 2018/8/27.
 */

public class Song {

    public Song() {

    }

    @Override
    public String toString() {
        return "东风破";
    }
}
package com.example.pengganggui.dagger2test;

/**
 * Created by pengganggui on 2018/8/27.
 * 艺术家
 */

public class Arthritis {

    Song song=null;

    Dance dance=null;

    public void play(){
        song=new Song();
        dance=new Dance();

        System.out.println("我是艺术家,我会跳"+song.toString()+"我会唱"+dance.toString());
    }
}

可以看见,在艺术家里需要new 两个对象才能实现相应的功能,这不符合软件开发的基本思想,低耦合,高内聚,比如说,此时,艺术家会的舞蹈歌曲不仅仅只是芭蕾舞和东风破了,那么我们需要修改Song和Dance类,因为Arthritis是和其紧紧依赖在一起的,所以,响应的Arthritis也需要改变,如果类多了,那么可以想象,工作量很大,并且还容易出错,代码的扩展性不大,这时候,依赖注入就应运而生了;

我们现在可以这么写:

package com.example.pengganggui.dagger2test;

import javax.inject.Inject;

/**
 * Created by pengganggui on 2018/8/27.
 * 舞蹈
 */

public class Dance {

    @Inject
    public Dance() {

    }

    @Override
    public String toString() {
        return "芭蕾舞";
    }
}
package com.example.pengganggui.dagger2test;

import javax.inject.Inject;

/**
 * Created by pengganggui on 2018/8/27.
 */

public class Song {

    @Inject
    public Song() {

    }

    @Override
    public String toString() {
        return "东风破";
    }
}
package com.example.pengganggui.dagger2test;

import javax.inject.Inject;

/**
 * Created by pengganggui on 2018/8/27.
 * 艺术家
 */

public class Arthritis {

    @Inject
    Song song=null;

    @Inject
    Dance dance=null;

    @Inject
    public Arthritis() {

    }

    public String play(){
        return "我是艺术家,我会跳"+song.toString()+"我会唱"+dance.toString();
    }
}

@Inject 注解就如同一个标签,或者说它是一个记号,它是给 Dagger2 看的。它运用的地方有两处。

  1. @Inject 给一个类的相应的属性做标记时,说明了它是一个依赖需求方,需要一些依赖。

  2. @Inject 给一个类的构造方法进行注解时,表明了它能提供依赖的能力。

但是,仔细想一想,@Inject可以标记一个属性需要一些依赖或者标记一个类可以提供依赖,但是这些依赖在哪呢,不知道,我需要一个依赖,你可以提供依赖,那么我给你提供依赖就可以了,但是,这两者之间仅仅通过@Inject一个注解是达不到效果的,所以,还需要一个@Component注解,来建立两者关系;

package com.example.pengganggui.dagger2test;

import dagger.Component;

/**
 * Created by pengganggui on 2018/8/27.
 */

@Component()
public interface ArthritisInterface {

    Arthritis play();
}

这样,就有了联系的纽带了,这时,我们在主活动调用:

package com.example.pengganggui.dagger2test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final Arthritis play = DaggerArthritisInterface.builder().build().play();
        findViewById(R.id.btn_test).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this,play.play(),Toast.LENGTH_LONG).show();
            }
        });
    }
}

所以,使用@Inject和@Component注解就可以使用Dagger2了;

但是,如果真的有这么简单的话,那么也不会让这么多人头疼了,所以,我们再想一想,@Inject需要注解在类的构造方法上,才能提供依赖,那么就有一个问题了,并不是所有的类我们都可以再其构造方法上添加@Inject的,比如第三方库和Java的标准库,这些都是不允许你修改的,这时,dagger2就提供了其它的注解;

@Provides 和 @Module

Provide 本身的字面意思就是提供,显然在 Dagger2 中它的作用就是提供依赖。 
Module 是模块的意思,Dagger2 中规定,用 @Provides 注解的依赖必须存在一个用 @Module 注解的类中。

我们改一改代码:此时艺术家不仅仅只会唱一首歌和一支舞了,我们需要动态的去改变歌名和舞名,我们可以这么写:

package com.example.pengganggui.dagger2test;

import javax.inject.Inject;

/**
 * Created by pengganggui on 2018/8/27.
 */

public class Song {

    String songName="";
    @Inject
    public Song() {
    }

    public Song(String songName){
        this.songName=songName;
    }

    @Override
    public String toString() {
        return songName;
    }
}
package com.example.pengganggui.dagger2test;

import javax.inject.Inject;

/**
 * Created by pengganggui on 2018/8/27.
 * 舞蹈
 */

public class Dance {

    String danceName="";
    @Inject
    public Dance() {
    }

    public Dance(String danceName) {
        this.danceName=danceName;
    }

    @Override
    public String toString() {
        return danceName;
    }
}
package com.example.pengganggui.dagger2test;

import dagger.Module;
import dagger.Provides;

/**
 * Created by pengganggui on 2018/8/27.
 */

@Module
public class ArthritisPlatform {

    @Provides
    public Song providesSong(){
        return new Song("我的太阳");
    }

    @Provides
    public Dance providesDance(){
        return new Dance("拉丁舞");
    }

}

这就是@Module和@Provides的用法,向外界提供依赖,那么Component里面怎么关联呢?

package com.example.pengganggui.dagger2test;

import dagger.Component;

/**
 * Created by pengganggui on 2018/8/27.
 */

@Component(modules = ArthritisPlatform.class)
public interface ArthritisInterface {

    Arthritis play();
}

这样就大功告成了,主活动的代码不需要改,同时要注意,当一个类同时被Modle和Inject提供,那么会以@Module为主;

上面四个注解足以应对大部分的日常的开发了,不过Dagger2提供的可不止这些:

@Singleton

用 @Singleton 标注在目标单例上,然后用 @Singleton 标注在 Component 对象上。就可以实现单例模式

@Singleton其实是被@Scope元注解注解的一个注解,那么@Scope其实就是代表作用域,他规定了这个注解的作用域的大小,我们上面说了,@Singleton需要标注在目标单例和component上,那么为什么需要标注在Component上呢,标注在Component上代表这个singleton只能在component的范围内有效;

猜你喜欢

转载自blog.csdn.net/pgg_cold/article/details/82110348