Dagger2

本文代码:
[DaggerExample]: https://github.com/zrfzhouruifeng163/DaggerExample

Dagger2是个啥?

一个依赖注入框架。(f....这是刷?哥们谷度吧)

Dagger2能解决啥问题?

进一步解耦
解耦? 看下下面的强耦合性代码

public class C {

    public void methodC() {
    }
}
public class Example01Activity extends AppCompatActivity {

    C c;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_example01);

        c = new C();//随便new
        c.methodC();
    }
}

Example01Activity强烈依赖C,如果C的构造方法发生变化,onCreate内的代码得发生变化。
直白的说即是,Example01Activity里new了C,dagger2作用是解耦,实际就是不让Example01Activity里newC 又能给C的实例赋值。
上升一步高度,在这里强耦合的描述是,调用者调用被调用者,Example01Activity调用C ,Example01Activity是调用者,C是被调用者,在调用者内直接new被调用者。使用dagger2后,new的过程被转移到dagger2中了,dagger2再把对象注入到Example01Activity中。
dagger2处理后,代码如下:-----example01

public class C {
    
    @Inject
    public C() {
    }

    public void methodC() {
        Log.e("c","ccc");
    }
}
@Component
public interface Example01ActivityComponent {

    void inject(Example01Activity activity);
}
public class Example01Activity extends AppCompatActivity {

    @Inject
    C c;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_example01);

        DaggerExample01ActivityComponent.create().inject(this);
        //这里的c没有new,就能直接使用了  啦啦啦
        c.methodC();
    }
}

冒然一看,上边代码貌似增加了代码量,其实真的是增加了代码量,但从逻辑上来看,的确没有在调用者中new了,勉强说是解耦了吧,虽然看起来没什么niao用。后续慢慢思考!

Dagger2的环境配置

作为一名安卓开发者,当前配置是

AndroidStudio 3.0.1
Android Plugin Version 2.3.1
Gradle version 3.3
----------------------------------------------
app下build.gradle
dependencies内增加:
compile 'com.google.dagger:dagger:2.14.1'
annotationProcessor 'com.google.dagger:dagger-compiler:2.14.1'

版本可以自己更改为最新,我就暂时用2.14.1了

常用的api清单

@Inject
@Component
@Module
@Qualifier
@Named
@Scope
@Singleton
@Lazy
@Provides
@IntoSet
@ElementsIntoSet
@IntoMap

大概有个印象,至于作用,后续慢慢说

有个前提

大家最好对注解和依赖注入有个了解,具体的可以自己谷度。

先从Inject和Component开始

@Inject   可以标注在三个地方
1.属性,表示我要往这个实例中注入对象,这是注入的目标。注意,该属性为非private的。
2.构造方法,表示我要用这个构造方法去生成对象,然后通过component注入到被Inject标注的属性上。注意,一个类中,只能有一个构造方法被标注。
3.方法上,可以理解为属性的set方式,也是注入的目标。

@Component   用该注解标注的接口,就是一个注入器,用于表示要往哪些类中注入,是一个入口。接口的命名方式:目标类+Component

@Inject标注在属性和构造方法上,实例代码如下 ----- example02

public class Book {

    //标注在构造方法上,表示我要用这个构造方法去生成对象
    @Inject
    public Book() {
    }

    public void read(){
        Log.e("book","read 水壶传");
    }
}


/**
 * 标注在接口上,表示这是一个注入器,针管儿,要打针啦
 * 要给PersonActivity打针,所以接口命名为PersonActivityComponent
 */
@Component
public interface PersonActivityComponent {

    //表示给哪个类注入,这里表示要给PersonActivity打针
    void inject(PersonActivity activity);
}


public class PersonActivity extends AppCompatActivity {

    //标注在属性上,表示我要往这个属性内注入对象,记得是非private的
    @Inject
    Book book;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_person);

        //在写这里之前记得先Build-make project下,在编译期内会生成一些代码
        //DaggerPersonActivityComponent就是在make后生成的,不make,是找不到这个类的,命名规则是:Dagger+component接口名
        //PersonActivity + Component
        //Dagger + PersonActivityComponent
        //清楚了没
        //言归正传,这里的作用是要给这个类注入内容
        DaggerPersonActivityComponent.create().inject(this);

        //直接调用方法就行了
        book.read();
    }
}

@Inject标注在方法上,实例代码如下 ------example03

public class Book {

    //标注在构造方法上,表示我要用这个构造方法去生成对象
    @Inject
    public Book() {
    }

    public void read(){
        Log.e("book","read 三国演义");
    }
}

/**
 * 标注在接口上,表示这是一个注入器,针管儿,要打针啦
 * 要给Person2Activity打针,所以接口命名为Person2ActivityComponent
 */
@Component
public interface Person2ActivityComponent {

    //表示给哪个类注入,这里表示要给PersonActivity打针
    void inject(Person2Activity activity);
}

public class Person2Activity extends AppCompatActivity {


    private Book book;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_person);

        //在写这里之前记得先Build-make project下,在编译期内会生成一些代码
        //DaggerPerson2ActivityComponent就是在make后生成的,不make,是找不到这个类的,命名规则是:Dagger+component接口名
        //Person2Activity + Component
        //Dagger + Person2ActivityComponent
        //清楚了没
        //言归正传,这里的作用是要给这个类注入内容
        DaggerPerson2ActivityComponent.create().inject(this);

        //直接调用方法就行了
        book.read();
    }

    //标注在方法上,类似set   表示我要往这个属性内注入对象,记得这里的属性可以是private的
    @Inject
    public void setBook(Book book){
        this.book = book;
        //这里就获取到了this,可以直接使用this了
        this.load();
    }

    //对象的方法
    public void load(){
        Log.e("load","hello world");
    }
}

@Inject在属性和方法上有啥异同?

1.二者都是给属性注入对象
2.标注在方法上,在方法内可以使用this关键字了,因为肯定是在调用完类的构造方法后才可以使用标注的方法,这时候当然有this了

可以想象下,标注在方法和属性上,可以同时使用吗?
of course --yes ------example04 如下:

public class Apple {

    //标注在构造方法上,表示我要用这个构造方法去生成对象
    @Inject
    public Apple() {
    }

    public void eat(){
        Log.e("apple","eat bugs");
    }
}

public class Book {

    //标注在构造方法上,表示我要用这个构造方法去生成对象
    @Inject
    public Book() {
    }

    public void read(){
        Log.e("book","read 三国演义");
    }
}


@Component
public interface Person3ActivityComponent {
    void inject(Person3Activity activity);
}

public class Person3Activity extends AppCompatActivity {

    @Inject
    Book book;

    private Apple apple;

    @Inject
    Apple apple2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_person3);

        DaggerPerson3ActivityComponent.create().inject(this);

        book.read();
        apple.eat();
        apple2.eat();
    }

    @Inject
    public void setApple(Apple apple) {
        this.apple = apple;
    }
}

Please think another question ---component可以同时给多个类注入吗?
of course ----yes ------example05

public class Book {

    //标注在构造方法上,表示我要用这个构造方法去生成对象
    @Inject
    public Book() {
    }

    public void read(){
        Log.e("book","read 三国演义");
    }
}

@Component
public interface Person4ActivityComponent {

    //给Person4Activity打针
    void inject(Person4Activity activity);

    //给Person5Activity打针
    void inject(Person5Activity activity);
}

public class Person4Activity extends AppCompatActivity {

    @Inject
    Book book;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_person4);

        DaggerPerson4ActivityComponent.create().inject(this);
        Log.e("tag","Person4Activity");
        book.read();

    }
}

public class Person5Activity extends AppCompatActivity {

    @Inject
    Book book;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_person5);

        DaggerPerson4ActivityComponent.create().inject(this);
        Log.e("tag","Person5Activity");
        book.read();

        Intent intent = new Intent(this,Person4Activity.class);
        startActivity(intent);
    }
}

再说@Module和@Provides

@Module:向 注入器 提供对象实例的类,想下@Inject作用在构造方法上,其作用就是向注入器提供构造对象的方法。@Module有相同的作用,只是换了一种方式,这是对@Inject的补充。
@Provides:与@Module配合使用的,标注在Module内的具体的提供对象的方法上。

描述个场景:

我们使用了两个类Apple和Book,但是Apple和Book分别来源于第三方的sdk,这时候 我们就没有办法在Apple和Book的构造上进行标注@Inject了,这时候又想使用dagger2 ,咋办呢,@Module来了。

看个实例代码----example06

//模拟来源于第三方sdk的类,不能修改其源码
public class Book {

    public Book() {
    }

    public void read(){
        Log.e("book","read 三国演义");
    }
}

//模拟来源于第三方sdk的类,不能修改其源码
public class Apple {

    public Apple() {
    }

    public void eat(){
        Log.e("apple","eat bugs");
    }
}

/**
 * 表示向构造器提供对象的类
 */
@Module
public class MyModule {

    //标注在方法上,表示具体的提供对象的方法,命名方式一般为:provide+具体要提供的类名
    @Provides
    Apple provideApple(){
        return new Apple();//这里需要new了
    }

    //标注在方法上,表示具体的提供对象的方法
    @Provides
    Book provideBook(){
        return new Book();//这里需要new了
    }
}

//这里的modules=Mydule.class   表示我这个注入器,从MyModule中寻找提供对象实例的方法
@Component(modules = MyModule.class)
public interface ModuleActivityComponent {

    void inject(ModuleActivity activity);
}

public class ModuleActivity extends AppCompatActivity {

    @Inject
    Apple apple;

    @Inject
    Book book;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_module);

        DaggerModuleActivityComponent.create().inject(this);

        apple.eat();
        book.read();
    }
}

描述下流程:

1.ModuleActivityComponent为入口,想要注入到目标类ModuleActivity中
2.发现ModuleActivity中有两个属性需要注入@Inject Apple  和@Inject Book
3.从哪儿找提供对象实例的的来源呢?发现component上有个modules=MyModule.class
4.去往Mymodule
5.找到了两个Provides方法,正好是provideApple 和 provideBook,ok,就这俩了
6.调用MyModule内的方法,然后给ModuleActivity中的俩属性注入实例。

OK,question,一个component可以多个module吗?
of course ---yes 实例代码如下 ------example07

//模拟来源于第三方sdk的类,不能修改其源码
public class Apple {

    public Apple() {
    }

    public void eat(){
        Log.e("apple","eat bugs");
    }
}

//模拟来源于第三方sdk的类,不能修改其源码
public class Book {

    public Book() {
    }

    public void read(){
        Log.e("book","read 三国演义");
    }
}

/**
 * 表示向构造器提供Apple对象的类
 */
@Module
public class AppleModule {

    //标注在方法上,表示具体的提供对象的方法
    @Provides
    Apple provideApple(){
        return new Apple();//这里需要new了
    }

}

/**
 * 表示向构造器提供Book对象的类
 */
@Module
public class BookModule {


    //标注在方法上,表示具体的提供对象的方法
    @Provides
    Book provideBook(){
        return new Book();//这里需要new了
    }
}

//多个module用这种方式
@Component(modules = {AppleModule.class,BookModule.class})
public interface Module01ActivityComponent {

    void inject(Module01Activity activity);
}

public class Module01Activity extends AppCompatActivity {

    @Inject
    Apple apple;

    @Inject
    Book book;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_module01);

        DaggerModule01ActivityComponent.create().inject(this);

        apple.eat();
        book.read();
    }
}

OK,question again,对接口声明的字段标注@Inject和对接口实现类的构造标注@Inject,能实现注入吗?看下面的代码----example08

public interface IAnimal {
    void bark();
}
public class Dog implements IAnimal {

    //这里对接口实现类的构造进行标注
    @Inject
    public Dog() {
    }
    public void bark(){
        Log.e("dog bark","汪汪汪");
    }
}
public class AnimalActivity extends AppCompatActivity {

    //这里对接口声明的字段标注
    @Inject
    IAnimal animal;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_animal);

        DaggerAnimalActivityComponent.create().inject(this);

        animal.bark();
    }
}
@Component
public interface AnimalActivityComponent {

    void inject(AnimalActivity activity);
}

The answer is NO. 会报错的,注入不了。
但是,接口的引用指向子类的对象,这是一种很常用的用法,该如何实现呢,---module啦,一切尽在code中。

public interface IAnimal {
    void bark();
}

public class Dog implements IAnimal {

    //这里不需要标注@Inject
    public Dog() {
    }
    public void bark(){
        Log.e("dog bark","汪汪汪");
    }
}

public class Cow implements IAnimal {

    //注意这里需要标注@Inject
    @Inject
    public Cow() {
    }

    @Override
    public void bark() {
        Log.e("cow bark","哞哞哞");
    }
}

@Module
public class AnimalModule {

    //方式一: 直接在提供的方法内new一个就行了   这时Dog的构造上不需要@Inject
//    @Provides
//    IAnimal provideAnimal(){
//        return new Dog();//new new new
//    }

    //方式二:在接口实现类Cow的构造上@Inject  ,在这里直接当参数传进来,即可
    //这里在参数中有Cow,会去寻找是否有Cow实例的方法,发现Cow的构造上有@Inject   使用。
    @Provides
    IAnimal provideAnimal(Cow cow){
        return cow;
    }
}

@Component(modules = AnimalModule.class)
public interface Animal2ActivityComponent {

    void inject(Animal2Activity activity);
}

public class Animal2Activity extends AppCompatActivity {

    @Inject
    IAnimal animal;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_animal2);

        DaggerAnimal2ActivityComponent.create().inject(this);

        animal.bark();

    }
}

在上面的AnimalModule中列出了方式一和方式二,两个provide方法,大家应该注意到了我把方式一给注释了,why?因为放开后,运行会报错,这当然是废话,为什么报错呢?我的理解是,一方面provide的方法不要重名,尽管符合重载原则,另一方面,因为在dagger2中,component会寻找对象构造来源,这个来源通常是唯一的,上面的方式一二 ,两个方法都是构造IAnimal的,可以说component找到了两个来源,然后就不知道选择哪个了,就报错了。
怎么解决呢?

引出@Named和@Qualifier

作用:
1.标记在provide方法上,用于区分来源。
2.标记在字段上,表示使用哪个来源。

先说@Named,代码如下,----example10

public class Oriange implements IFruit{
    @Inject
    public Oriange() {
    }

    @Override
    public void name() {
        Log.e("name","oriange");
    }
}

public class Banana implements IFruit{
    @Override
    public void name() {
        Log.e("name","banananana");
    }
}

public class Pear implements IFruit {

    public String name = "China";
    @Inject  //注意构造方法上不能打@Named
    public Pear() {
        name = "China";
    }


    public Pear(String name) {
        this.name = name;
    }

    @Override
    public void name() {
        Log.e("name",name);
    }
}

@Module
public class FruitModule {

    @Provides
    @Named("banana")//打标记,标记来源,用于区分
    IFruit provideBanana(){
        return new Banana();
    }

    @Provides
    @Named("oriange")//打标记,标记来源,用于区分
    IFruit provideOriange(Oriange oriange){
        return oriange;
    }

    @Provides
    @Named("pear2")
    Pear providePear(){
        Log.e("from","module pear");
        return new Pear("America");
    }
}

@Component(modules = FruitModule.class)
public interface FruitActivityComponent {
    void inject(FruitActivity activity);
}

public class FruitActivity extends AppCompatActivity {


    @Inject
    @Named("banana")   //标记是用哪个来源进行注入
    IFruit banana;

    @Inject
    @Named("oriange")   //标记是用哪个来源进行注入
    IFruit oriange;

    @Inject   //对应的是Pear中的构造方法上的@Inject   注意构造方法上不能打@Named
    Pear pear1;

    @Inject
    @Named("pear2")   //对应的是FruitModule中的方法
    Pear pear2;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fruit2);

        DaggerFruitActivityComponent.create().inject(this);

        banana.name();
        oriange.name();

        pear1.name();
        pear2.name();
    }
}

再说@Qualifier ,也是标记来源,@Named是通过字符串来唯一确定,而@Qualifier是通过定义注解来区分,具体做法是,定义一个注解,然后在该注解上标注@Qualifier,然后将该注解标注在构造器来源和@Inject标注的字段上。不同的来源定义不同的注解。
二者的区别是,Named需要手动去写这个唯一标示,Qualifier则是直接定义,省去了写字符串的过程,更加简洁。
代码如下----example11

public class Bird {

    public String name;

    public Bird(String name) {
        this.name = name;
    }

    public void name(){
        Log.e("name=",name);
    }
}

/**
 * 定义一个注解,并标注@Qualifier,这里定义的是标注parrot来源的注解
 */
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface ParrotQualifier {
}


/**
 * 定义一个注解,并标注@Qualifier,这里定义的是标注sparrow来源的注解
 */
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface SparrowQualifier {
}

@Module
public class BirdModule {

    //不同的来源标注不同的Qualifier,用于区分

    @Provides
    @SparrowQualifier    //标注sparrow注解,表示这是sparrow对象的来源
    Bird provideBird1(){
        return new Bird("sparrow");
    }

    @Provides
    @ParrotQualifier  //标注parot注解,表示这是parrot对象的来源
    Bird provideBird2(){
        return new Bird("parrot");
    }
}

@Component(modules = BirdModule.class)
public interface BirdActivityComponent {

    void inject(BirdActivity activity);
}


public class BirdActivity extends AppCompatActivity {

    @Inject
    @SparrowQualifier  //标注sparrow注解,表示要使用被SparrowQualifier标注的来源,注入到该字段
    Bird sparrow;

    @Inject
    @ParrotQualifier  //标注parrot注解,表示要使用被ParrotQualifier标注的来源,注入到该字段
    Bird parrot;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bird);

        DaggerBirdActivityComponent.create().inject(this);

        sparrow.name();
        parrot.name();
    }
}

@Inject @Module @Component的工作流程

dagger2.png

文字叙述:

1.component为入口
2.inject确定被注入的目标类(如XXXActivity)
3.在目标类中确认有哪些被@Inject标注的字段或方法需要被注入实例。
4.回到component,查看是否有module
5.有module
    5.1查看module中是否有提供依赖的provide方法
    5.2有提供依赖的provide方法
        5.2.1 方法上没有参数,则直接利用这个方法创建对象,注入到目标字段
        5.2.2 方法上有参数,那么此时该参数也是需要被注入的字段(等效于被@Inject标注了),那么此时就需要从步骤1的component开始,寻找能为此参数提供依赖的标注,一直找到为止,然后利用该参数所在的方法,创建对象,注入到目标字段中。
    5.3没有提供依赖的provide方法,则从6.1开始
6.无module
    6.1在各个类中寻找被@Inject标注的构造方法
    6.2没有找到能提供依赖的被@Inject标注的构造方法,则报错,证明没有可以提供依赖的来源。
    6.3找到了提供依赖的@Inject构造方法
    6.4查看该构造方法上是否有参数
    6.5构造上没有参数,则直接利用此构造创建对象,然后注入到目标字段上
    6.6构造上有参数,那么此时该参数也是需要被注入的字段(等效于被@Inject标注了),那么此时就需要从步骤1的component开始,寻找能为此参数提供依赖的标注,一直找到为止,然后继续进行利用参数所在的构造函数进行创建对象,然后注入到目标字段上。

@Scope

scope有范围、余地的意思,被scope标注的类,在一定范围内能达到单例的效果,即只创建一次,多次使用都是同一个对象。
@Scope的源码如下:

@Target(ANNOTATION_TYPE)
@Retention(RUNTIME)
@Documented
public @interface Scope {}

ANNOTATION_TYPE 表示Scope只能标注在注解上。
需要注意:

1.@Scope是用于自定义注解的,只能标注在注解上。
2.被@Scope自定义出来的注解,是可以标注在类、方法和Component上的
Scope使用方式一:

Scope标注在类以及Component上
步骤:

1.使用@Scope自定义一个注解@MyScope
2.将@MyScope标注在类上
3.将@MyScope标注在Component上
4.使用Component进行注入实现即可

实例代码如下 ---example12

/**
 * Scope只能标注在注解上
 * 这里自定义一个Scope
 */
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface MyScope {
}

/**
 * 注意是这个类上标注了自定义的一个主机@MyScope
 */
@MyScope
public class Laptop {
    //构造上标注了@Inject
    @Inject
    public Laptop() {
        Log.e("laptop","laptop");
    }
}

/**
 * 这里没有标注自定义的@MyScope
 */
public class Mobile {
    //构造上标注了@Inject
    @Inject
    public Mobile() {
        Log.e("mobile","mobile");
    }
}

@MyScope   //注意要在这里标注@MyScope,因为目标类ScopeActivity中,有个被@Inject标注的字段,而这个字段所属的类被@MyScope标注了,所以这个Component必须标注
@Component
public interface ScopeActivityComponent {
    void inject(ScopeActivity activity);
}

public class ScopeActivity extends AppCompatActivity {

    @Inject
    Laptop laptop01;
    @Inject
    Laptop laptop02;

    @Inject
    Mobile mobile01;
    @Inject
    Mobile mobile02;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scope);

        DaggerScopeActivityComponent.create().inject(this);

        log(laptop01.hashCode()+"");
        log(laptop02.hashCode()+"");
        log(mobile01.hashCode()+"");
        log(mobile02.hashCode()+"");
    }

    private void log(String msg){
        Log.e("msg",msg);
    }
}

结果如下:

com.zhourf.dagger.daggerexample E/laptop: laptop
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/msg: 186183467
com.zhourf.dagger.daggerexample E/msg: 186183467
com.zhourf.dagger.daggerexample E/msg: 146743176
com.zhourf.dagger.daggerexample E/msg: 2886945

可以看出:
被MyScope标注的Laptop类,构造方法只执行了一次,而laptop01和laptop02的地址值是同一个
没有被MyScope标注的Mobile类,构造方法执行了两次,mobile01和mobile02的地址值不同。

此外,刚才在上面描述时,有一句话,“在一定范围内能达到单例的效果”,那么这个范围是什么呢?
先看代码:---example12

/**
 * Scope只能标注在注解上
 * 这里自定义一个Scope
 */
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface MyScope {
}

/**
 * 注意是这个类上标注了自定义的一个主机@MyScope
 */
@MyScope
public class Laptop {
    //构造上标注了@Inject
    @Inject
    public Laptop() {
        Log.e("laptop","laptop");
    }
}

/**
 * 这里没有标注自定义的@MyScope
 */
public class Mobile {
    //构造上标注了@Inject
    @Inject
    public Mobile() {
        Log.e("mobile","mobile");
    }
}

@MyScope   //注意要在这里标注@MyScope,因为目标类ScopeActivity中,有个被@Inject标注的字段,而这个字段所属的类被@MyScope标注了,所以这个Component必须标注
@Component
public interface ScopeActivityComponent {
    void inject(ScopeActivity activity);
}

public class ScopeActivity extends AppCompatActivity {

    @Inject
    Laptop laptop01;
    @Inject
    Laptop laptop02;

    @Inject
    Mobile mobile01;

    @Inject
    Mobile mobile02;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scope);

        DaggerScopeActivityComponent.create().inject(this);

        log(laptop01.hashCode()+"");
        log(laptop02.hashCode()+"");
        log(mobile01.hashCode()+"");
        log(mobile02.hashCode()+"");

        startActivity(new Intent(this,Scope2Activity.class));
    }

    private void log(String msg){
        Log.e("msg",msg);
    }
}

@MyScope
@Component
public interface Scope2ActivityComponent {

    void inject(Scope2Activity activity);

    void inject(Scope3Activity activity);
}

public class Scope2Activity extends AppCompatActivity {

    @Inject
    Laptop laptop03;
    @Inject
    Laptop laptop04;

    @Inject
    Mobile mobile03;

    @Inject
    Mobile mobile04;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scope2);

        DaggerScope2ActivityComponent.create().inject(this);

        log(laptop03.hashCode()+"");
        log(laptop04.hashCode()+"");
        log(mobile03.hashCode()+"");
        log(mobile04.hashCode()+"");
    }

    private void log(String msg){
        Log.e("msg",msg);
    }
}

public class Scope3Activity extends AppCompatActivity {

    @Inject
    Laptop laptop05;
    @Inject
    Laptop laptop06;

    @Inject
    Mobile mobile05;

    @Inject
    Mobile mobile06;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scope3);

        DaggerScope2ActivityComponent.create().inject(this);

        log(laptop05.hashCode()+"");
        log(laptop06.hashCode()+"");
        log(mobile05.hashCode()+"");
        log(mobile06.hashCode()+"");
    }

    private void log(String msg){
        Log.e("msg",msg);
    }
}

结果如下:

com.zhourf.dagger.daggerexample E/laptop: laptop
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/msg: 186183467
com.zhourf.dagger.daggerexample E/msg: 186183467
com.zhourf.dagger.daggerexample E/msg: 146743176
com.zhourf.dagger.daggerexample E/msg: 2886945

com.zhourf.dagger.daggerexample E/laptop: laptop
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/msg: 106306550
com.zhourf.dagger.daggerexample E/msg: 106306550
com.zhourf.dagger.daggerexample E/msg: 91425783
com.zhourf.dagger.daggerexample E/msg: 128682596

com.zhourf.dagger.daggerexample E/laptop: laptop
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/msg: 76555776
com.zhourf.dagger.daggerexample E/msg: 76555776
com.zhourf.dagger.daggerexample E/msg: 16014905
com.zhourf.dagger.daggerexample E/msg: 98020478

在上面的的代码中,使用了ScopeActivityComponent 注入ScopeActivity,使用Scope2ActivityComponent,分别注入Scope2Activity和Scope3Activity,每个Activity中分别声明了Laptop和Mobile的两个字段。启动ScopeActivity后,会自动跳转到Scope2Activity,Scope2Activity自动跳转Scope3Activity
可以看出结果:
在ScopeActivity中:

com.zhourf.dagger.daggerexample E/laptop: laptop
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/msg: 186183467
com.zhourf.dagger.daggerexample E/msg: 186183467
com.zhourf.dagger.daggerexample E/msg: 146743176
com.zhourf.dagger.daggerexample E/msg: 2886945

Laptop构造执行了一次,两个laptop的地址相同
Mobile构造执行了两次,两个mobile的地址不同

在跳转到Scope2Activity后:

com.zhourf.dagger.daggerexample E/laptop: laptop
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/msg: 106306550
com.zhourf.dagger.daggerexample E/msg: 106306550
com.zhourf.dagger.daggerexample E/msg: 91425783
com.zhourf.dagger.daggerexample E/msg: 128682596

Laptop的构造重新执行了,且一次,两个laptop地址相同,又与ScopeActivity中的laptop地址不同
Mobile的构造重新执行了,两次,两个mobile地址不同,与ScopeActivity中的mobile地址不同。

在Scope3Activity中:

com.zhourf.dagger.daggerexample E/laptop: laptop
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/msg: 76555776
com.zhourf.dagger.daggerexample E/msg: 76555776
com.zhourf.dagger.daggerexample E/msg: 16014905
com.zhourf.dagger.daggerexample E/msg: 98020478

Laptop的构造重新执行了,且一次,两个laptop地址相同,又与ScopeActivity和Scope2Activity中的laptop地址不同
Mobile的构造重新执行了,两次,两个mobile地址不同,与ScopeActivity和Scope2Activity中的mobile地址不同。

结论:

1.@Scope是用于自定义注解的
2.@MyScope 必须同时标注在类上和对应的Component上。
3.被@MyScope标注后,在Component注入的同一个目标范围内,可以达到单例的表现效果,如果Component注入了多个目标,那么各自目标内,可以单例。但是多个目标不能共享单例。
Scope使用方式二

将自定义Scope标注在方法和Component上
步骤

1.使用@Scope自定义注解@TestScope
2.将@TestScope标注在module的provide方法上
3.将@TestScope标注在component上
4.使用Component进行注入实现。

示例代码如下,---example13

public class Green {

    public Green() {
        Log.e("green construct","green");
    }
}

@Module
public class TestModule {

    @TestScope  //标注在provide方法上   只会取一次
    @Provides
    Green provideGreen(){
        Log.e("green provide","green");
        return new Green();
    }

}

@TestScope
@Component(modules = TestModule.class)
public interface ColorActivityComponent {

    void inject(ColorActivity activity);
}

public class ColorActivity extends AppCompatActivity {

    @Inject
    Green green1;
    @Inject
    Green green2;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_color);

        DaggerColorActivityComponent.create().inject(this);

        log(green1.hashCode());
        log(green2.hashCode());
    }

    private void log(int msg){
        Log.e("color",msg+"");
    }
}

运行结果:

com.zhourf.dagger.daggerexample E/green provide: green
com.zhourf.dagger.daggerexample E/green construct: green
com.zhourf.dagger.daggerexample E/color: 186183467
com.zhourf.dagger.daggerexample E/color: 186183467
Scope使用方式三

自定义注解,标注在类、component和provide上,混合使用。
示例代码 ,-----example13

//自定义一个Scope注解
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface TestScope {
}

public class Green {

    public Green() {
        Log.e("green construct","green");
    }
}

public class Red {

    public Red() {
        Log.e("red construct","red");
    }
}

public interface IBlue {
}
@TestScope
public class Blue implements IBlue {

    @Inject
    public Blue() {
        Log.e("blue construct","blue");
    }
}

public interface IOrange {
}
@TestScope
public class Orange implements IOrange {

    @Inject
    public Orange() {
        Log.e("Orange construct","Orange");
    }
}

@Module
public class TestModule {

    @TestScope
    @Provides
    Green provideGreen(){
        Log.e("green provide","green");
        return new Green();
    }

    @Provides
    Red provideRed(){
        Log.e("red provide","red");
        return new Red();
    }

    @Provides
    IBlue provideBlue(Blue blue){
        Log.e("blue provide","blue");
        return blue;
    }

    @TestScope
    @Provides
    IOrange provideOrange(Orange orange)
    {Log.e("orange provide","orange");
        return orange;
    }
}

@TestScope
@Component(modules = TestModule.class)
public interface ColorActivityComponent {

    void inject(ColorActivity activity);
}

public class ColorActivity extends AppCompatActivity {

    @Inject
    Green green1;
    @Inject
    Green green2;

    @Inject
    Red red1;
    @Inject
    Red red2;

    @Inject
    IBlue blue1;
    @Inject
    IBlue blue2;

    @Inject
    IOrange orange1;
    @Inject
    IOrange orange2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_color);

        DaggerColorActivityComponent.create().inject(this);


        log("green1",green1.hashCode());
        log("green2",green2.hashCode());
        log("red1",red1.hashCode());
        log("red2",red2.hashCode());
        log("blue1",blue1.hashCode());
        log("blue2",blue2.hashCode());
        log("orange1",orange1.hashCode());
        log("orange2",orange2.hashCode());
    }

    private void log(String tag,int msg){
        Log.e(tag,msg+"");
    }
}

结果如下:

com.zhourf.dagger.daggerexample E/green provide: green
com.zhourf.dagger.daggerexample E/green construct: green
com.zhourf.dagger.daggerexample E/red provide: red
com.zhourf.dagger.daggerexample E/red construct: red
com.zhourf.dagger.daggerexample E/red provide: red
com.zhourf.dagger.daggerexample E/red construct: red
com.zhourf.dagger.daggerexample E/blue construct: blue
com.zhourf.dagger.daggerexample E/blue provide: blue
com.zhourf.dagger.daggerexample E/blue provide: blue
com.zhourf.dagger.daggerexample E/Orange construct: Orange
com.zhourf.dagger.daggerexample E/orange provide: orange
com.zhourf.dagger.daggerexample E/green1: 186183467
com.zhourf.dagger.daggerexample E/green2: 186183467
com.zhourf.dagger.daggerexample E/red1: 146743176
com.zhourf.dagger.daggerexample E/red2: 2886945
com.zhourf.dagger.daggerexample E/blue1: 122148166
com.zhourf.dagger.daggerexample E/blue2: 122148166
com.zhourf.dagger.daggerexample E/orange1: 112546567
com.zhourf.dagger.daggerexample E/orange2: 112546567

结果分析

Green ,@TestScope标注在component和provide上,Green及构造上什么都不标注
com.zhourf.dagger.daggerexample E/green provide: green
com.zhourf.dagger.daggerexample E/green construct: green
com.zhourf.dagger.daggerexample E/green1: 186183467
com.zhourf.dagger.daggerexample E/green2: 186183467
调用了一次provide和一次构造,两个green的地址相同

Red,@TestScope只标注在component上,Red类及构造及provide上什么都不标注
com.zhourf.dagger.daggerexample E/red provide: red
com.zhourf.dagger.daggerexample E/red construct: red
com.zhourf.dagger.daggerexample E/red provide: red
com.zhourf.dagger.daggerexample E/red construct: red
com.zhourf.dagger.daggerexample E/red1: 146743176
com.zhourf.dagger.daggerexample E/red2: 2886945
调用了两次provide和两次构造,两个red对象地址不同,所以只标注在component上,没什么用

Blue,@TestScope标注在component及Blue类上,Blue构造标注@Inject,provide方法上什么都不标注
com.zhourf.dagger.daggerexample E/blue construct: blue
com.zhourf.dagger.daggerexample E/blue provide: blue
com.zhourf.dagger.daggerexample E/blue provide: blue
com.zhourf.dagger.daggerexample E/blue1: 122148166
com.zhourf.dagger.daggerexample E/blue2: 122148166
调用了两次provide和一次构造,两个blue对象地址相同,因为provide没有标注@TestScope,所以调用了两次,而类上标注了@TestScope,所以构造只执行了一次。

Orange,@TestScope同时标注在Component、provide和Orange类上
com.zhourf.dagger.daggerexample E/Orange construct: Orange
com.zhourf.dagger.daggerexample E/orange provide: orange
com.zhourf.dagger.daggerexample E/orange1: 112546567
com.zhourf.dagger.daggerexample E/orange2: 112546567
调用了一次构造和一次provide,两个oriange对象地址相同。provide优先级比类高,所以取到provide就一次了。

其实也就是说:
1.自定义Scope,单独标注类或provide上,都有“单例效果”。
2.自定义Scope,同时标注在类和provide上,provide优先级高。
3.component上必须标注Scope,才有效果。

然后再说@Singleton

@Scope
@Documented
@Retention(RUNTIME)
public @interface Singleton {}

这其实就是@Scope自定义注解的一种实现,和我们上面定义的@TestScope是一样的。

Lazy

一看这个词,就能想到懒加载,其含义也是类似的,在使用时再去加载。
1.在@Inject Lazy 时,不会去调用依赖来源创建对象
2.在@Inject T t时,就直接取调用来源创建对象了
3.如果有两个@Inject Lazy 那么两个Lazy之间完全独立,互不影响。
4.Lazy的get方法是获取T对象,当一个Lazy第一次get时,调用依赖来源创建对象,然后缓存,当第二次get时,获取的是缓存的对象,而不会再去调用依赖来源创建对象
5.两个Lazy不会共享缓存
示例代码 ----example14

public class HuaWei {

    @Inject
    public HuaWei() {
        Log.e("huawei","huawei");
    }
}
@Component
public interface HuaweiActivityComponent {
    void inject(HuaweiActivity activity);
}

public class HuaweiActivity extends AppCompatActivity {

    @Inject
    HuaWei hw1;//这时就直接调用依赖来源去创建对象了

    @Inject
    Lazy lhw1;//此时没有调用依赖来源去创建对象

    @Inject
    Lazy lhw2;//此时没有调用依赖来源去创建对象

    @Inject
    HuaWei hw2;//这时就直接调用依赖来源去创建对象了

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_huawei);

        DaggerHuaweiActivityComponent.create().inject(this);

        Log.e("start","--------------------");
        log("hw1",hw1.hashCode());
        log("lhw1",lhw1.get().hashCode());//当第一次调用get时,才调用依赖来源去创建对象,然后缓存起来
        log("lhw1",lhw1.get().hashCode());//当第二次调用get时,使用第一次的缓存
        log("hw2",hw2.hashCode());
        log("lhw2",lhw2.get().hashCode());//当第一次调用get时,才调用依赖来源去创建对象,然后缓存起来。需要注意的是两个Lazy是完全独立的,不会共享缓存
        log("lhw2",lhw2.get().hashCode());//当第二次调用get时,使用第一次的缓存
    }

    private void log(String tag,int msg){
        Log.e(tag,msg+"");
    }
}

运行结果:

com.zhourf.dagger.daggerexample E/huawei: huawei  //@Inject时就调用了构造
com.zhourf.dagger.daggerexample E/huawei: huawei //@Inject时就调用了构造
com.zhourf.dagger.daggerexample E/start: --------------------
com.zhourf.dagger.daggerexample E/hw1: 186183467
com.zhourf.dagger.daggerexample E/huawei: huawei   //get时才去调用构造函数
com.zhourf.dagger.daggerexample E/lhw1: 146743176
com.zhourf.dagger.daggerexample E/lhw1: 146743176//第二次get就不调用构造了
com.zhourf.dagger.daggerexample E/hw2: 2886945
com.zhourf.dagger.daggerexample E/huawei: huawei  //第二个Lazy的第一次get时,调用构造
com.zhourf.dagger.daggerexample E/lhw2: 122148166
com.zhourf.dagger.daggerexample E/lhw2: 122148166 //第二次get不调用构造

Provider

Provider ,字面意思 ,提供者。
1.使用@Inject Provider 时,不会立即调用构造函数。
2.当使用Provider.get()时才去调用构造函数,同时不会缓存对象
3.当使用第二次Provider.get(),会立即调用构造函数。
4.也就是说每次调用Provider.get()时都会调用构造函数,重新创建对象,就像一个T的工厂一样,源源不断生成,且每次都是new的 。
示例代码 example15

public class Table {

    @Inject
    public Table() {
        Log.e("table construct","table");
    }
}

@Component
public interface TableActivityComponent {
    void inject(TableActivity activity);
}

public class TableActivity extends AppCompatActivity {

    @Inject
    Provider provider1;//此时没有调用构造函数
    @Inject
    Provider
provider2;//此时没有调用构造函数 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_table); DaggerTableActivityComponent.create().inject(this); Log.e("tag","----------"); log("provider1 get1",provider1.get().hashCode());//此时调用构造函数,不缓存 log("provider1 get2",provider1.get().hashCode());//此时依然调用构造函数,重新创建 log("provider2 get1",provider2.get().hashCode());//此时调用构造函数,不缓存 log("provider2 get2",provider2.get().hashCode());//此时依然调用构造函数,重新创建 } private void log(String tag,int msg){ Log.e(tag,msg+""); } }

运行结果:

com.zhourf.dagger.daggerexample E/tag: ----------
com.zhourf.dagger.daggerexample E/table construct: table
com.zhourf.dagger.daggerexample E/provider1 get1: 186183467
com.zhourf.dagger.daggerexample E/table construct: table
com.zhourf.dagger.daggerexample E/provider1 get2: 146743176
com.zhourf.dagger.daggerexample E/table construct: table
com.zhourf.dagger.daggerexample E/provider2 get1: 2886945
com.zhourf.dagger.daggerexample E/table construct: table
com.zhourf.dagger.daggerexample E/provider2 get2: 122148166

Set

@IntoSet 将一个值add入set
1.标注在provide方法上,可以将provide方法的返回值add到Set中。
2.使用@Inject Set set 字段 ,可以从provide方法取得依赖。
3.相同返回值的多个provide方法,最终都会将值存到同一个Set内。
4.都使用@IntoSet标注,且返回值不同的provide方法,会将值存到各自的Set Set中。
5.一个component,inject多个目标类时,共享这个Set。
@ElementsIntoSet 将多个值add入set
1.与@IntoSet功能类似,也是往Set中add值。
2.@IntoSet是一个一个值的add,@ElementsIntoSet则是一次可以add多个。
3.也是标注在provide方法上,但是其返回值是Set类型。
注意:
对于二者,同一个component内,不论module多少,Set共享,就是同一个T的,用的都是同一个Set
不同的component之间,Set独立不共享。
实例代码 ----example16

public class Desk {
    public String name;
    public Desk(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Desk{" +
                "name='" + name + '\'' +
                '}';
    }
}

public class Chair {
    public String name;
    @Override
    public String toString() {
        return "Chair{" +
                "name='" + name + '\'' +
                '}';
    }
    public Chair(String name) {
        this.name = name;
    }
}

@Module
public class DeskModule {

    @Provides
    @IntoSet   //这里的Desk会被放到Set中    对应的返回值其实是Set
    Desk provideDesk(){
        return new Desk("   DeskModule   intoset dest1");
    }

    @Provides
    @IntoSet  //这里的Desk会被放到Set中,且是同一个set,就算跨Activity了也是同一个     对应的返回值其实是Set
    Desk provideDesk3(){
        return new Desk("DeskModule   intoset dest2");
    }

    @Provides
    @IntoSet  //这里的Chair会被放到Set中     对应的返回值其实是Set
    Chair provideChair(){
        return new Chair("DeskModule   intoset chair1");
    }

    @Provides
    @ElementsIntoSet   //这里的Chair会被放到Set中  且是同一个Set   对应的返回值其实是Set
    Set provideSetChair(){
        Set set = new HashSet<>();
        set.add(new Chair(" DeskModule   elementsIntoSet  chair2"));
        set.add(new Chair("DeskModule   elementsIntoSet   chair3"));
        return set;
    }

    @Provides  //返回值是Desk
    Desk provideDesk2(){
        return new Desk("DeskModule   desk3");
    }

    @Provides
    @IntoSet   //这里的Chair会被放到Set中  且是同一个Set   对应的返回值其实是Set
    String provideName(){
        return "DeskModule   aaaa";
    }
}

@Module
public class Desk2Module {

    @Provides
    @IntoSet  //这个返回值是Set   也会被放到Set中   且与DeskModule中的是同一个Set
    Desk provideDesk(){
        return new Desk("Desk2Module   intoset 2dest4");
    }

    @Provides
    @IntoSet  //这个返回值是Set   也会被放到Set中   且与DeskModule中的是同一个Set
    Chair provideChair(){
        return new Chair("Desk2Module   intoset 2chair4");
    }

    @Provides
    @ElementsIntoSet   //这个返回值是Set   也会被放到Set中   且与DeskModule中的是同一个Set
    Set provideSetChair(){
        Set set = new HashSet<>();
        set.add(new Chair("Desk2Module   ElementsIntoSet 2chair5"));
        set.add(new Chair("Desk2Module   ElementsIntoSet  2hair6"));
        return set;
    }


    @Provides
    @IntoSet//这个返回值是Set   也会被放到Set中   且与DeskModule中的是同一个Set
    String provideName(){
        return "Desk2Module   2bbbb";
    }
}

@Component(modules = {DeskModule.class,Desk2Module.class})
public interface SetActivityComponent {

    void inject(SetActivity activity);
    void inject(DeskActivity activity);
}

public class SetActivity extends AppCompatActivity {

    @Inject
    Set ss;

    @Inject
    Set sd;

    @Inject
    Set sc;

    @Inject
    Desk d;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_set);

        DaggerSetActivityComponent.create().inject(this);
        Log.e("start","---------");

        for(String str:ss){
            Log.e("ss=",str);
        }

        for(Desk d :sd){
            Log.e("sd=",d.toString());
        }

        for(Chair c : sc)
        {
            Log.e("sc=",c.toString());
        }

        Log.e("d=",d.toString());

        startActivity(new Intent(this,DeskActivity.class));
    }
}

public class DeskActivity extends AppCompatActivity {

    @Inject
    Set ss;

    @Inject
    Set sd;

    @Inject
    Set sc;

    @Inject
    Desk d;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_desk);

        DaggerSetActivityComponent.create().inject(this);
        Log.e("start","deskActivity---------");

        for(String str:ss){
            Log.e("ss=",str);
        }

        for(Desk d :sd){
            Log.e("sd=",d.toString());
        }

        for(Chair c : sc)
        {
            Log.e("sc=",c.toString());
        }

        Log.e("d=",d.toString());

        //startActivity(new Intent(this,ChairActivity.class));
    }
}

代码说明:
DeskModule内,使用@IntoSet @ElementsIntoSet 返回了Set Set Set ,示例值都是以DeskModule开头

Desk2Module内,使用@IntoSet @ElementsIntoSet 返回了Set Set Set ,示例值都是以Desk2Module开头

SetActivityComponent中,module={DeskModule,Desk2Module}
且inject(SetActivity) 和 inject(DeskActivity)

SetActivity 和DeskActivity 中分别对Set Set Set 进行访问

结果显示是两个module中的Desk Chair String 都add到了同一个Set Set Set 中了,说明同一个component多个module是共用一个Set
运行结果:

SetActivity内log的结果:
com.zhourf.dagger.daggerexample E/start: ---------
com.zhourf.dagger.daggerexample E/ss=: DeskModule   aaaa
com.zhourf.dagger.daggerexample E/ss=: Desk2Module   2bbbb
com.zhourf.dagger.daggerexample E/sd=: Desk{name='   DeskModule   intoset dest1'}
com.zhourf.dagger.daggerexample E/sd=: Desk{name='DeskModule   intoset dest2'}
com.zhourf.dagger.daggerexample E/sd=: Desk{name='Desk2Module   intoset 2dest4'}
com.zhourf.dagger.daggerexample E/sc=: Chair{name='Desk2Module   ElementsIntoSet  2hair6'}
com.zhourf.dagger.daggerexample E/sc=: Chair{name='DeskModule   intoset chair1'}
com.zhourf.dagger.daggerexample E/sc=: Chair{name='Desk2Module   ElementsIntoSet 2chair5'}
com.zhourf.dagger.daggerexample E/sc=: Chair{name='Desk2Module   intoset 2chair4'}
com.zhourf.dagger.daggerexample E/sc=: Chair{name='DeskModule   elementsIntoSet   chair3'}
com.zhourf.dagger.daggerexample E/sc=: Chair{name=' DeskModule   elementsIntoSet  chair2'}
com.zhourf.dagger.daggerexample E/d=: Desk{name='DeskModule   desk3'}

DeskActivity内log的结果,与上面是一样的。
com.zhourf.dagger.daggerexample E/start: deskActivity---------
com.zhourf.dagger.daggerexample E/ss=: DeskModule   aaaa
com.zhourf.dagger.daggerexample E/ss=: Desk2Module   2bbbb
com.zhourf.dagger.daggerexample E/sd=: Desk{name='Desk2Module   intoset 2dest4'}
com.zhourf.dagger.daggerexample E/sd=: Desk{name='   DeskModule   intoset dest1'}
com.zhourf.dagger.daggerexample E/sd=: Desk{name='DeskModule   intoset dest2'}
com.zhourf.dagger.daggerexample E/sc=: Chair{name='DeskModule   elementsIntoSet   chair3'}
com.zhourf.dagger.daggerexample E/sc=: Chair{name=' DeskModule   elementsIntoSet  chair2'}
com.zhourf.dagger.daggerexample E/sc=: Chair{name='Desk2Module   ElementsIntoSet 2chair5'}
com.zhourf.dagger.daggerexample E/sc=: Chair{name='Desk2Module   intoset 2chair4'}
com.zhourf.dagger.daggerexample E/sc=: Chair{name='DeskModule   intoset chair1'}
com.zhourf.dagger.daggerexample E/sc=: Chair{name='Desk2Module   ElementsIntoSet  2hair6'}
com.zhourf.dagger.daggerexample E/d=: Desk{name='DeskModule   desk3'}


在上面的代码基础上,增加一个ChairActivityComponent-ChairModule-ChairActivity
如下代码:

@Module
public class ChairModule {

    @Provides
    @IntoSet
    Desk provideDesk3(){
        return new Desk("ChairModule  desk---");
    }

    @Provides
    @ElementsIntoSet
    Set provideDesks(){
        Set s = new HashSet<>();
        s.add(new Desk("ChairModule   ElementsIntoSet  desk///"));
        s.add(new Desk("ChairModule   ElementsIntoSet  desk+++"));
        return s;
    }
}

@Component(modules = ChairModule.class)
public interface ChairActivityComponent {

    void inject(ChairActivity activity);
}

public class ChairActivity extends AppCompatActivity {

//    @Inject
//    Set ss;

    @Inject
    Set sd;

//    @Inject
//    Set sc;
//
//    @Inject
//    Desk d;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chair);

        DaggerChairActivityComponent.create().inject(this);

        Log.e("start","ChairActivity---------");

//        for(String str:ss){
//            Log.e("ss=",str);
//        }

        for(Desk d :sd){
            Log.e("sd=",d.toString());
        }

//        for(Chair c : sc)
//        {
//            Log.e("sc=",c.toString());
//        }

//        Log.e("d=",d.toString());
    }
}

运行结果如下

com.zhourf.dagger.daggerexample E/start: ChairActivity---------
com.zhourf.dagger.daggerexample E/sd=: Desk{name='ChairModule   ElementsIntoSet  desk+++'}
com.zhourf.dagger.daggerexample E/sd=: Desk{name='ChairModule  desk---'}
com.zhourf.dagger.daggerexample E/sd=: Desk{name='ChairModule   ElementsIntoSet  desk///'}

ChairActivityComponent与SetActivityComponent是独立的,在ChairModule只是增加了Set,在ChairActivity中只能访问Set 且值只是ChairModule中增加的。说明了 两个component之间Set是独立的,互不影响。

IntoMap

@IntoSet是将同一个T的值存到一个Set中,看@IntoMap,应该也明白是将值存到一个Map中,只是增加了key。key的表示也是用注解的形式,如@StringKey @ClassKey

示例代码如下 example17

public class Mouse {
    public String name;

    @Override
    public String toString() {
        return "Mouse{" +
                "name='" + name + '\'' +
                '}';
    }

    public Mouse(String name) {
        this.name = name;
    }
}

@Module
public class MouseModule {

    @Provides
    @IntoMap
    @StringKey("key01")
    Mouse provideMouse(){   //注意这里的返回值是T
        return new Mouse("mouse01");
    }

    @Provides
    @IntoMap
    @StringKey("key02")
    Mouse provideMouse2(){
        return new Mouse("mouse02");
    }
}

@Component(modules = MouseModule.class)
public interface MapActivityComponent {
    void inject(MapActivity activity);
}

public class MapActivity extends AppCompatActivity {

    @Inject  //这里用这种方式注入结果  
    Map map;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_map);

        DaggerMapActivityComponent.create().inject(this);

        for(Map.Entry entry : map.entrySet()){
            Log.e(entry.getKey(),entry.getValue().toString());
        }
    }
}

运行结果:

com.zhourf.dagger.daggerexample E/key01: Mouse{name='mouse01'}
com.zhourf.dagger.daggerexample E/key02: Mouse{name='mouse02'}

结果显示,module中的两个provide方法都将值into中了map,key也是各自定义的。
扩展:::
1.一个component,多个module,则Map共用吗?
2.provideMouse方法 能放到Map中吗?
示例代码, example17

public class Mouse {
    public String name;

    @Override
    public String toString() {
        return "Mouse{" +
                "name='" + name + '\'' +
                '}';
    }

    public Mouse(String name) {
        this.name = name;
    }
}

public class KeyBoard {
    public String name;

    @Override
    public String toString() {
        return "KeyBoard{" +
                "name='" + name + '\'' +
                '}';
    }

    public KeyBoard(String name) {
        this.name = name;
    }
}

@Module
public class MouseModule {

    @Provides
    @IntoMap
    @StringKey("key01")
    Mouse provideMouse(){
        return new Mouse("mouse01");
    }

    @Provides
    @IntoMap
    @StringKey("key02")
    Mouse provideMouse2(){
        return new Mouse("mouse02");
    }

}

@Module
public class Mouse2Module {

    @Provides
    @IntoMap
    @StringKey("key03")
    Mouse provideMouse3(){
        return new Mouse("mouse03");
    }

    @Provides
    @IntoMap
    @ClassKey(Mouse.class)
    Mouse provideMouse4(){
        return new Mouse("mouse04");
    }

    @Provides
    @IntoMap
    @ClassKey(MouseModule.class)
    KeyBoard provideMouse5(){
        return new KeyBoard("keyboard01");
    }

    @Provides
    @IntoMap
    @ClassKey(Mouse2Module.class)
    Object provideMouse6(){
        return new KeyBoard("object");
    }
}

@Component(modules = {MouseModule.class,Mouse2Module.class})
public interface MapActivityComponent {
    void inject(MapActivity activity);
}

public class MapActivity extends AppCompatActivity {

    @Inject
    Map map;

    @Inject
    Map,Mouse > map2;

    @Inject
    Map,KeyBoard> map3;

    @Inject
    Map,Object> map4;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_map);

        DaggerMapActivityComponent.create().inject(this);

        Log.e("tag","-----------");
        for(Map.Entry entry : map.entrySet()){
            Log.e(entry.getKey(),entry.getValue().toString());
        }
        Log.e("tag","-----------");
        for(Map.Entry,Mouse> entry : map2.entrySet()){
            Log.e(entry.getKey().getName(),entry.getValue().toString());
        }
        Log.e("tag","-----------");
        for(Map.Entry,KeyBoard> entry : map3.entrySet()){
            Log.e(entry.getKey().getName(),entry.getValue().toString());
        }
        Log.e("tag","-----------");
        for(Map.Entry,Object> entry : map4.entrySet()){
            Log.e(entry.getKey().getName(),entry.getValue().toString());
        }
    }
}

运行结果:

com.zhourf.dagger.daggerexample E/tag: -----------
com.zhourf.dagger.daggerexample E/key01: Mouse{name='mouse01'}
com.zhourf.dagger.daggerexample E/key02: Mouse{name='mouse02'}
com.zhourf.dagger.daggerexample E/key03: Mouse{name='mouse03'}
com.zhourf.dagger.daggerexample E/tag: -----------
com.zhourf.dagger.daggerexample E/com.zhourf.dagger.daggerexample.example17.Mouse: Mouse{name='mouse04'}
com.zhourf.dagger.daggerexample E/tag: -----------
com.zhourf.dagger.daggerexample E/com.zhourf.dagger.daggerexample.example17.MouseModule: KeyBoard{name='keyboard01'}
com.zhourf.dagger.daggerexample E/tag: -----------
com.zhourf.dagger.daggerexample E/com.zhourf.dagger.daggerexample.example17.Mouse2Module: KeyBoard{name='object'}

结论:
1.在同一个component内,无论几个module,都共用同一个类型的Map
2.Map的key与value的类型严格对应,这里不适用“接口的引用指向子类的对象”这句话。

再次扩展:如果是两个component,注入到两个类中呢?-example18

@Module
public class Map1Module {

    @Provides
    @IntoMap
    @StringKey("key01")
    String provideStr1(){
        return "value01";
    }
}
@Component(modules = {Map1Module.class})
public interface Map1ActivityComponent {
    void inject(Map1Activity activity);
}
public class Map1Activity extends AppCompatActivity {

    @Inject
    Map map;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_map1);

        DaggerMap1ActivityComponent.create().inject(this);


        Log.e("tag","Map1Activity-----------1111");
        for(Map.Entry entry:map.entrySet())
        {
            Log.e(entry.getKey(),entry.getValue());
        }

        startActivity(new Intent(this,Map2Activity.class));
    }
}

@Module
public class Map2Module {

    @Provides
    @IntoMap
    @StringKey("key02")
    String provideStr1(){
        return "value02";
    }
}

@Component(modules = {Map2Module.class})
public interface Map2ActivityComponent {
    void inject(Map2Activity activity);
}
public class Map2Activity extends AppCompatActivity {
    @Inject
    Map map;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_map2);

        DaggerMap2ActivityComponent.create().inject(this);


        Log.e("tag","Map2Activity-----------222");
        for(Map.Entry entry:map.entrySet())
        {
            Log.e(entry.getKey(),entry.getValue());
        }
    }
}

运行结果:

com.zhourf.dagger.daggerexample E/tag: Map1Activity-----------1111
com.zhourf.dagger.daggerexample E/key01: value01
com.zhourf.dagger.daggerexample E/tag: Map2Activity-----------222
com.zhourf.dagger.daggerexample E/key02: value02

可以看到两个component的情况下,Map是各自独立的。

扩展:如何自定义Map的key?
在注释类型中声明的方法的返回类型,必须符合下列类型:

1.基本数据类型
2.String
3.Class
4.枚举类型
5.注解类型
6.以上数据类型的数组

看一个示例,example19

//自定义个枚举
public enum TestEnum {
    A,B,C,D
}

//自定义Map的key,方法返回值是枚举
@MapKey
public @interface CustKey {
    TestEnum value();
}

@Module
public class TestModule {
    @Provides
    @IntoMap
    @CustKey(TestEnum.A)
    String provideStrA(){
        return "aaa";
    }

    @Provides
    @IntoMap
    @CustKey(TestEnum.B)
    String provideStrB(){
        return "bbb";
    }
}

@Component(modules = TestModule.class)
public interface KeyActivityComponent {
    void inject(KeyActivity activity);
}

public class KeyActivity extends AppCompatActivity {

    @Inject
    Map map;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_key);

        DaggerKeyActivityComponent.create().inject(this);

        for(Map.Entry entry:map.entrySet())
        {
            Log.e(entry.getKey().toString(),entry.getValue());
        }
    }
}

运行结果:

com.zhourf.dagger.daggerexample E/A: aaa
com.zhourf.dagger.daggerexample E/B: bbb

@Component的dependencies

试想下:
Component1提供了 A B C的依赖
Component2提供了 D E F的依赖
那么在一个目标类内@Inject A a;@Inject D d了,那么怎么实现?
其实就是,每个component都有各自的提供依赖功能,怎么使用的问题。
大家都知道Component(modules = {}) 中module的作用,其实还有个dependencies,也是类似的功能,区别在于 :modules=Module类,dependencies=其他的Component ,这样就把其他component的功能引入到自身了。
看下实例 example21

public class Table {
    @Inject
    public Table() {
    }

    public void name(){
        Log.e("Table tag","Table");
    }
}

@Module
public class TableModule {
    @Provides
    Table provideTable(){
        return new Table();
    }
}

@Component(modules = TableModule.class)
public interface TableComponent {
    //这么定义,会从所依赖的module中寻找
    //一般是供其他component依赖时这么定义
    Table getTable();
}

public class Cup {
    @Inject
    public Cup() {
    }

    public void name(){
        Log.e("cup tag","cups");
    }
}

@Module
public class CupModule {
    @Provides
    Cup provideCup(){
        return new Cup();
    }
}

//注意这里的dependencies
@Component(modules = CupModule.class,dependencies = TableComponent.class)
public interface CupActivityComponent {

    void inject(CupActivity activity);
}

public class CupActivity extends AppCompatActivity {

    @Inject
    Cup cup;

    @Inject
    Table table;//在TableComponent 中可以找到依赖来源

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_cup);

        DaggerCupActivityComponent
                .builder()
                .tableComponent(DaggerTableComponent.create())//因为CupActivityComponent  dependencies了TableComponent,所以这里需要传入TableComponent的实例
                .build()
                .inject(this);

        cup.name();
        table.name();
    }
}

运行结果:

com.zhourf.dagger.daggerexample E/cup tag: cups
com.zhourf.dagger.daggerexample E/Table tag: Table

@Subcomponent

看名字,就猜个大概,Component 的 sub ,sub 子的意思。
这其实也是Component的一种依赖方式。
更确切的说,subcomponent 继承了Component的依赖,并拥有自己的依赖。
比如:
Component1 可以提供A B C 依赖
Subcomponent1 可以提供 D E 依赖
SubComponent2 可以提供 F依赖
那么:Subcomponent1 的inject的目标类中,可以提供ABCDE依赖
SubComponent2的inject的目标类中,可以提供ABCF依赖
注意:字的Component上必须标注为@Subcomponent
看示例代码 example22

提供全局的Application的Component
首先自定义DaggerApplication,并在AndroidManifest中做修改
public class DaggerApplication extends Application {
    private static DaggerApplication instance;

    @Override
    public void onCreate() {
        super.onCreate();
        instance = this;
    }
    public static DaggerApplication getInstance(){
        return instance;
    }
}

提供Application的Module
@Module
public class ApplicationModule {
    @Provides
    DaggerApplication provideApplication(){
        return DaggerApplication.getInstance();
    }
}

定义类Lion  及其module component
public class Lion {
    public Lion() {
    }
    public void roar(){
        Log.e("lion","lion");
    }
}
@Module
public class LionModule {

    @Provides
    Lion provideLion()
    {
        return new Lion();
    }
}
//注意这里是Subcomponent
@Subcomponent(modules = LionModule.class)
public interface LionComponent {
   void inject(AnimalActivity activity);
}

定义类Tiger  及其module component
public class Tiger {

    public Tiger() {
    }
    public void roar()
    {
        Log.e("roar","tiger");
    }
}
@Module
public class TigerModule {

    @Provides
    Tiger provideTiger()
    {
        return new Tiger();
    }
}
//注意这里是sub
@Subcomponent(modules = TigerModule.class)
public interface TigerComponent {
    void inject(TigerActivity activity);
}

定义基Component,并将Lion和TigerComponent置为此的sub
@Component(modules = ApplicationModule.class)
public interface AnimalActivityComponent {
    LionComponent plus();
    TigerComponent plus2();
}

看一个Activity
public class AnimalActivity extends AppCompatActivity {

    @Inject
    Lion lion;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_animal3);
        
        DaggerAnimalActivityComponent.builder().build()//获取基Component
                .getLion()//获取子component  LionComponent
                .inject(this);  //注入此地
        lion.roar();

        startActivity(new Intent(this,TigerActivity.class));
    }
}

public class TigerActivity extends AppCompatActivity {
//自身提供的依赖
    @Inject
    Tiger tiger;

    //获取了基Component提供的依赖,这样就获取到了全局的一个application
    @Inject
    DaggerApplication application;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tiger);

        AnimalActivityComponent component = DaggerAnimalActivityComponent.builder().build();
        Log.e("tag", "TigerActivity......");
        component.getTiger().inject(this);
        tiger.roar();
        Log.e("tag", "applicaion=" + application.getPackageName());
    }
}

运行结果:

com.zhourf.dagger.daggerexample E/lion: lion
com.zhourf.dagger.daggerexample E/tag: TigerActivity......
com.zhourf.dagger.daggerexample E/roar: tiger
com.zhourf.dagger.daggerexample E/tag: applicaion=com.zhourf.dagger.daggerexample

你可能感兴趣的:(Dagger2)