Dagger2 学习笔记 Module使用和理解

上一篇结尾说道如果有参数的调用应该是怎么来写呢?

最后的报错说明一个类的构造好函数只有一个被@Inject标注

前面说过

@Module:@Module用于封装提供依赖的类。为什么需要专门提供这个注解,因为在很多情况下,我们需要注入的类是第三方类库,我们无法再构造函数直接加@Inject注解,还有一个问题就是如果有多个构造函数的问题,Module封装依赖就是为了解决这些问题。

这里我们就需要使用Module了,首先我们先看下如果是第三方库类的注入

@Module
public class DateModule {
    int mid;

    public DateModule(int id) {
        mid = id;
    }

    @Provides
    public Phone providePhone(){
        return new Phone(mid);//这里假设Phone是第三方库里面的类
    }

    @Provides
    public Book provideBook(){
        return new Book(mid);//这里假设Book是第三方库里面的类
    }

}

这里新建一个DataModule类用@Module标注

他有两个方法providePhone和provideBook都用@Provides标注,然后接下来还需要一个步骤继续看BookComponent

@Component(modules = {DateModule.class})
public interface BookComponent {

    void inject(MainActivity activity);

}

这里@Component加了参数modules参数,可以表明对外提供的是那个Module,这里可以写多个Module

下面我们就看下调用方式

public class MainActivity extends AppCompatActivity {

    @Inject
    Book mBook;
    @Inject
    Phone mPhone;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerBookComponent.builder()
                .dateModule(new DateModule(0))
                .build()
                .inject(this);
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e("wangyudong", "mBook: " + mBook.toString());
                Log.e("wangyudong", "mPhone: " + mPhone.toString());
            }
        });
    }
}

可以看出来区别就在于这里的DaggerBookComponent的Builder需要传入一个DateModule作为参数,来初始化Dagger

到这里就可以完成第三方类的注入了

2.第二个问题,如果有多个构造器呢?

这里就需要用到一个新的注解

@Qulifier:@Qulifier用于自定义注解,也就是说@Qulifier就如同Java提供的几种基本元注解一样用来标记注解类。我们在使用@Module来标注提供依赖的方法时,方法名我们是可以随便定义的(虽然我们定义方法名一般以provide开头,但这并不是强制的,只是为了增加可读性而已)。那么Dagger2怎么知道这个方法是为谁提供依赖呢?答案就是返回值的类型,Dagger2根据返回值的类型来决定为哪个被@Inject标记了的变量赋值。但是问题来了,一旦有多个一样的返回类型Dagger2就懵逼了。@Qulifier的存在正式为了解决这个问题,我们使用@Qulifier来定义自己的注解,然后通过自定义的注解去标注提供依赖的方法和依赖需求方(也就是被@Inject标注的变量),这样Dagger2就知道为谁提供依赖了。----一个更为精简的定义:当类型不足以鉴别一个依赖的时候,我们就可以使用这个注解标示;

一句话这个注解是一个原注解,用来生成自定义注解,因为Dagger解析的时候是通过@provide的返回值来匹配的,如果有多个函数返回值一样,dagger就不知道该用那个来生成实例了,因此用不同的自定义注解,把相同返回值类型的方法区别开来

正式用一下,自定义两个注解

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface BookQualifierC1 {
}

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface BookQualifierC2 {
}

使用自定义注解

@Module
public class DateModule {
    int mid;
    String mName;

    public DateModule(int id, String name) {
        mid = id;
        mName = name;
    }

    @Provides
    public Phone providePhone(){
        return new Phone(mid);
    }
    @BookQualifierC1
    @Provides
    public Book provideBookC1(){
        return new Book(mid);
    }
    @BookQualifierC2
    @Provides
    public Book provideBookC2(){
        return new Book(mid, mName);
    }

}

用自定义注解标记变量

public class MainActivity extends AppCompatActivity {

    @BookQualifierC2 @Inject Book mBook;
    @Inject
    Phone mPhone;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerBookComponent.builder()
                .dateModule(new DateModule(0, "哈利波特"))
                .build()
                .inject(this);
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e("wangyudong", "mBook: " + mBook.mName);
                Log.e("wangyudong", "mPhone: " + mPhone.toString());
            }
        });
    }
}

这样就mBook的实例就是通过调用两个参数的构造函数来获取的

到此就基本可以满足大多数的对象的注入了

3.最后 还有两个注解@Scope和@SingleTon

Scope中文意思范围的意思,我能可以通过@Scope自定义的注解来限定注解作用域,实现局部的单例;

@Singleton 其实就是一个通过@Scope定义的注解,我们一般通过它来实现全局单例。但实际上它并不能提前全局单例,是否能提供全局单例还要取决于对应的Component是否为一个全局对象。一般都是通过在Application里面通过Builder产品Daggerxxx类,然后其他地方都调用这个Component来作为一个全局的对象来使用,保证了真正的单例




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章