Dagger2的使用与理解(2)

接下来我们来看看@Module注解和@Provides注解,他们两个是在一起配合使用的。
@Module这个注解是用来修饰类对象的,表示这个类是个模板类,里面的@Provides修饰的方法的返回值用来提供依赖,所以@Provides修饰的方法必须不能是void,否则编译会报错。
这里写图片描述
为什么要使用这两个注解呢?
因为使用@Inject标记构造器提供依赖是有局限性的,比如说我们需要注入的对象是第三方库提供的,我们无法在第三方库的构造器上加上@Inject注解。
或者是需要注入的对象是抽象的,@Inject也无法使用,因为抽象的类并不能实例化。因为我们依赖的生成是直接通过new 出来,抽象类无法直接实现,因为生成代码无法确定抽象方法的实现。详情请见Dagger2的使用与理解(1)
首先我们新建一个Module类,这里用来为Activity提供Module,所以命名为ActivityModule,ActivityModule用@Module修饰表示这是个模板类,里面有两个用@Provides修饰的方法,分别用来提供String类型的依赖和Person类型的依赖。这里Person是个抽象类,Men类和Woman类继承Person类。
Dagger2的使用与理解(2)_第1张图片

@Module
public class ActivityModule {
    @Provides
    public String obtain(){
        return "1234";
    }

    @Provides
    public Person privodePerson(){
        return new Women();
    }
}
//抽象Person类实现
public abstract class Person {
}

//具体实现的子类--男人类
public class Men extends Person {
}

//具体实现的子类--女人类
public class Women extends Person {
}

在对应的注入器添加@Component里面的参数,参数就是用@Module修饰的Module类对象。

@Component(modules = ActivityModule.class)
public interface ActivityComponent {
    void inject(DaggerActivity daggerActivity);
}

在Activity注入

public class DaggerActivity extends AppCompatActivity {

    @Inject
    String sss;

    @Inject
    Person person;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_gui_view);
        DaggerActivityComponent.create().inject(this);
        Log.e("TAG", "sss = " + sss);
        Log.e("TAG", "person = " + person);
    }
}

打印输出的结果是 sss = 1234 person = 引用值,说明成员变量已经被注入依赖Dagger2的使用与理解(2)_第2张图片
@Module需要和@Provides是需要一起使用的时候才具有作用的,@Module是告诉Component,可以从这里获取依赖对象。Component就会去找被@Provide标注的方法,相当于构造器的@Inject,可以提供依赖。
还有一点要说的是,@Component可以指定多个@Module的,如果需要提供多个依赖的话。

@Component(modules = {Module1.class, Module2.class})
public interface ActivityComponent {
    void inject(DaggerActivity daggerActivity);
}

那么他在DaggerActivityComponent方法是怎么注入的呢,首先在成员变量多了两个Provider对象,也就是我们在Module类写的返回方法的依赖。

  private Provider obtainProvider;
  private Provider privodePersonProvider;
  private MembersInjector daggerActivityMembersInjector;

接下去看他们的初始化,在initialize方法,将module对象传入。

private void initialize(final Builder builder) {  
    this.obtainProvider = ActivityModule_ObtainFactory.create(builder.activityModule);
    this.privodePersonProvider = ActivityModule_PrivodePersonFactory.create(builder.activityModule);
    this.daggerActivityMembersInjector = DaggerActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), obtainProvider, privodePersonProvider);
  }

而Module是Builder的成员变量,可以外部传入Module,也可以通过build()方法创建。

  public static final class Builder {
    private ActivityModule activityModule;

    private Builder() {  
    }

    public ActivityComponent build() {  
      if (activityModule == null) {
        this.activityModule = new ActivityModule();
      }
      return new DaggerActivityComponent(this);
    }

    public Builder activityModule(ActivityModule activityModule) {  
      if (activityModule == null) {
        throw new NullPointerException("activityModule");
      }
      this.activityModule = activityModule;
      return this;
    }

上面创建的Module传入Provider的工厂实现上,我们重点看一下get方法,他将返回module.obtain()的返回值,而这个函数就是我们之前用@Provides注解标记的方法,return “1234”。Person的Provider实现同String。最后在注入的依赖的时候就能够将module类中用@Provides注解标记的方法的返回值赋值给注入对象。

public final class ActivityModule_ObtainFactory implements Factory<String> {
  private final ActivityModule module;

  public ActivityModule_ObtainFactory(ActivityModule module) {  
    assert module != null;
    this.module = module;
  }

  @Override
  public String get() {  
    String provided = module.obtain();
    if (provided == null) {
      throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
    }
    return provided;
  }

  public static Factory create(ActivityModule module) {  
    return new ActivityModule_ObtainFactory(module);
  }
}

这里注意一点,我们可以这么去写,在ActivityComponent 中加入provideB()和provideStr()方法,发现编译成功。其实这也是ActivityComponent 一个重要的功能,他能显示把项目里的依赖提供出来,暴露出去。B就是有@Inject标注构造器的依赖,String就是ActivityModule里面的”1234”。

@Component(modules = ActivityModule.class)
public interface ActivityComponent {
    void inject(DaggerActivity daggerActivity);

    B provideB();

    String provideStr();
}
@Override
  public B provideB() {  
    return B_Factory.create().get();
  }

  @Override
  public String provideStr() {  
    return obtainProvider.get();
  }

@Qualifier和@Named这两个注解是用来区分同类依赖的,@Qualifier是限定符,而@Named则是基于String的限定符。
当我有两个相同的依赖(都继承某一个父类或者都是先某一个接口)可以提供给高层时,那么程序就不知道我们到底要提供哪一个依赖,因为它找到了两个。
这时候我们就可以通过限定符为两个依赖分别打上标记,指定提供某个依赖。举个栗子:

//修改ActivityModule代码,其余代码不变
@Module
public class ActivityModule {
    @Provides
    public String obtain(){
        return "1234";
    }

    @Provides
    public Person privodeWoman(){
        return new Women();
    }

    @Provides
    public Person privodeMan(){
        return new Men();
    }
}

编译出错
这里写图片描述
因为在不知道用哪个Person(是来自privodeWoman(),还是来自privodeMan())依赖来注入。解决办法如下:

@Provides
    @Named("woman")
    public Person privodeWoman(){
        return new Women();
    }

    @Provides
    @Named("man")
    public Person privodeMan(){
        return new Men();
    }

注入的时候在person上面加上@Named(“woman”),person就会被注入Woman的实例。

//这里选择Woman,女士优先嘛
@Inject
    @Named("woman")
    Person person;

或者使用@Qualifier,@Qualifier不是直接注解在属性上的,而是用来自定义注解的。

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

我们新建两个注解@ManQualifier,@WomanQualifier,
这里写图片描述

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface ManQualifier {

}

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface WomanQualifier {

}

这个Module类改为:

@Module
public class ActivityModule {
    @Provides
    public String obtain(){
        return "1234";
    }

    @Provides
    @WomanQualifier
    public Person privodeWoman(){
        return new Women();
    }

    @Provides
    @ManQualifier
    public Person privodeMan(){
        return new Men();
    }
}

在person类上面用@ManQualifier注解修饰,这样就能把Man的实例注入到person中。

@Inject
    @ManQualifier
    Person person;

今天就写这些吧。。。。

你可能感兴趣的:(android)