Dagger2的使用与理解(2)

来源:互联网 发布:数据防泄密方案 编辑:程序博客网 时间:2024/05/29 02:30

接下来我们来看看@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类。
这里写图片描述

@Modulepublic 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 = 引用值,说明成员变量已经被注入依赖这里写图片描述
@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<String> obtainProvider;  private Provider<Person> privodePersonProvider;  private MembersInjector<DaggerActivity> 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<String> 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代码,其余代码不变@Modulepublic 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)@Documentedpublic @interface Qualifier {}

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

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

这个Module类改为:

@Modulepublic 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;

今天就写这些吧。。。。

原创粉丝点击