Dagger中的注解

@Module

@Module注解在类或接口上,表明该类或接口用于提供相关依赖。该类或接口中使用的注解有@Provides,@Binds,@IntoSet,@IntoMap。

@Provides

最常用,注解在非抽象方法上,返回值是程序中需要用到的依赖。
代码:


@Module
public class ProvidesModule {
  /*  形式一:自己构建Windable实例
     @Provides
    public Windable provideWindable(){
        return new WindableImpl();
    }*/

    /**
     * 形式二:让Dagger构建Windable实例,此时需要在WindableImpl构造函数上打上@Inject注解
     */
    @Provides
    public Windable provideWindable(WindableImpl windable){
        return windable;
    }
}

针对@Provides注解,编译期Dagger会生成格式为:
Module类名_方法名Factory 的类并且实现了Factory接口。
针对本例生成的类就是ProvidesModule_ProvideWindableFactory

public final class ProvidesModule_ProvideWindableFactory implements Factory<Windable> {
  private final ProvidesModule module;

  private final Provider<WindableImpl> windableProvider;

  public ProvidesModule_ProvideWindableFactory(
      ProvidesModule module, Provider<WindableImpl> windableProvider) {
    this.module = module;
    this.windableProvider = windableProvider;
  }

  @Override
  public Windable get() {
    return provideInstance(module, windableProvider);
  }

  public static Windable provideInstance(
      ProvidesModule module, Provider<WindableImpl> windableProvider) {
    return proxyProvideWindable(module, windableProvider.get());
  }

  public static ProvidesModule_ProvideWindableFactory create(
      ProvidesModule module, Provider<WindableImpl> windableProvider) {
    return new ProvidesModule_ProvideWindableFactory(module, windableProvider);
  }

  public static Windable proxyProvideWindable(ProvidesModule instance, WindableImpl windable) {
    return Preconditions.checkNotNull(
        instance.provideWindable(windable),
        "Cannot return null from a non-@Nullable @Provides method");
  }
}

生成的类的格式也是相对固定的。
一个静态create方法,返回值是该Factory类实例。
一个构造函数。
一个get方法,来自Factory接口,用于返回依赖。

注意:每个用@Provides注解的方法都会生成相应的Factory类。

@Binds

也是用于提供依赖,跟@Provides注解功能一样。不同的是@Binds注解于抽象方法上,返回值是依赖的接口或父类型或本类型,方法只有一个参数,就是返回值的实现者。既然@Binds注解于抽象方法,那么@Module注解的类就必须是接口或抽象类了。
代码:

@Module
public interface BindsModule {
    /**
     * 注解于抽象方法,只能有一个参数
     * @param windable
     * @return
     */
    @Binds
    Windable provideWindable(WindableImpl windable);
}

@IntoSet

@IntoSet需要联合@Provides一起使用,@IntoSet注解的方法表示方法返回值放入一个Set集合中,多个@IntoSet注解的方法,若方法返回值类型一致,则会放入同一个Set集合中。

@Module
public class IntoSetModule {

    @Provides
    @IntoSet
    public String provideA(){
        return "A";
    }

    @Provides
    @IntoSet
    public String provideB(){
        return "B";
    }
}

public class IntoSetDemo {

    @Inject
    Set<String> letters;
    IntoSetDemo(){
    }
    public static void main(String[] args){
        IntoSetDemo demo=new IntoSetDemo();
        DaggerIntoSetComponent.create().inject(demo);

        for (String letter:demo.letters){
            System.out.print(letter);
        }
    }
}

Module类中的provideA和provideB方法的返回值被放入同一个Set集合中,所以该例的输出结果是AB。

@IntoMap

@IntoMap需要联合@IntKey,@StringKey或者自定义的@MapKey以及@Provides一起使用。如果map的key为int类型,则用@IntKey,为String类型,则用@StringKey,如果为其他类型,则需要自定义注解,并在自定义注解上打上@MapKey。

@Module
public class IntoMapModule {

    @Provides
    @IntoMap
    @IntKey(1)
    public String provideNameA(){
        return "nameA";
    }

    @Provides
    @IntoMap
    @IntKey(2)
    public String provideNameB(){
        return "nameB";
    }
}

public class IntoMapDemo {

    @Inject
    Map<Integer,String> map;
    IntoMapDemo(){
    }
    public static void main(String[] args){
        IntoMapDemo demo=new IntoMapDemo();
        DaggerIntoMapComponent.create().inject(demo);

      System.out.println("key=1,value="+demo.map.get(1));
      System.out.println("key=2,value="+demo.map.get(2));
    }
}

IntoMapModule类中的provideNameA方法指定了key为1,value为nameA,provideNameB方法指定了key为2,value为nameB,他们被放入同一个map中。所以程序的输出结果是

key=1,value=nameA
key=2,value=nameB

@Component

@Component 注解的类(一般是接口或抽象类)用于为具体的类注入依赖。
@Component 注解有两个属性:
一个是modules属性,关联相关的Module
一个是dependencies属性,关联子Component

一般需要提供一个inject()方法,参数是需要注入的类;当然也可以定义一个直接获取依赖的方法,比如Activity类中需要注入一个Presenter对象,可以直接在Component接口中定义一个presenter方法,在Activity类中需要使用Presenter时使用component.presenter()就可以了。
a.inject法:

@Component(modules = MyModule.class)
public interface MyComponent {

    /**
     * 定义一个inject方法,注入ComponentDemo需要的依赖
     * @param componentDemo
     */
    void inject(ComponentDemo componentDemo);
}

public class ComponentDemo {

    @Inject
    MyService myService;

    ComponentDemo(){
    }

    public static void main(String args[]){
        ComponentDemo componentDemo=new ComponentDemo();
        //将MyService注入
        DaggerMyComponent.create().inject(componentDemo);
        componentDemo.myService.serve();
    }
}

MyModule提供了MyService实例。

b.Component提供一个myService()方法

@Component(modules = MyModule.class)
public interface MyComponent {
    //定义一个方法提供依赖
    MyService myService();
}
public class ComponentDemo {
    MyService myService;
    ComponentDemo(){
    }

    public static void main(String args[]){
        ComponentDemo componentDemo=new ComponentDemo(); 
        componentDemo.myService=DaggerMyComponent
                  .create()    
                  .myService();
        componentDemo.myService.serve();
    }
}

@Component注解在编译期生成的源码格式:
1,实现@Component注解的接口
2,静态内部类Builder,含有用于设置@Component注解中modules的方法
3,生成的Component类名为@Component注解的接口的简单名称加前缀Dagger。
4,一个接收builder的构造函数,保存相关的module。
5,实现@Component注解的接口中定义的方法

@Generated(
  value = "dagger.internal.codegen.ComponentProcessor",
  comments = "https://google.github.io/dagger"
)
public final class DaggerMyComponent implements MyComponent {
  private MyModule myModule;

  private DaggerMyComponent(Builder builder) {
    initialize(builder);
  }

  public static Builder builder() {
    return new Builder();
  }

  public static MyComponent create() {
    return new Builder().build();
  }

  @SuppressWarnings("unchecked")
  private void initialize(final Builder builder) {
    this.myModule = builder.myModule;
  }

  @Override
  public MyService myService() {
    return MyModule_ProvideMyServiceFactory.proxyProvideMyService(myModule);
  }

  public static final class Builder {
    private MyModule myModule;

    private Builder() {}

    public MyComponent build() {
      if (myModule == null) {
        this.myModule = new MyModule();
      }
      return new DaggerMyComponent(this);
    }

    public Builder myModule(MyModule myModule) {
      this.myModule = Preconditions.checkNotNull(myModule);
      return this;
    }
  }
}

@Inject

当@Inject标注在构造器时,说明该类的实例交由Dagger生成,Dagger会在编译期间生成一个XXX_Factory类。
当@Inject标注在字段上时,Dagger会在编译期生成一个XXX_MembersInjector类。

public class MapKeyDemo {


    @Inject
    Map<Bar,Integer> map;

    private String param;
    @Inject
    public MapKeyDemo(String param){
        this.param=param;
    }

    public static void main(String [] args){
        MapKeyComponent mapKeyComponent=DaggerMapKeyComponent.create();
        MapKeyDemo mapKeyDemo=mapKeyComponent.mapKeyDemo();
        mapKeyComponent.inject(mapKeyDemo);
    }

}

生成的类


@Generated(
  value = "dagger.internal.codegen.ComponentProcessor",
  comments = "https://google.github.io/dagger"
)
public final class MapKeyDemo_Factory implements Factory<MapKeyDemo> {
  private final Provider<String> paramProvider;

  private final Provider<Map<Bar, Integer>> mapProvider;

  public MapKeyDemo_Factory(
      Provider<String> paramProvider, Provider<Map<Bar, Integer>> mapProvider) {
    this.paramProvider = paramProvider;
    this.mapProvider = mapProvider;
  }

  @Override
  public MapKeyDemo get() {
    return provideInstance(paramProvider, mapProvider);
  }

  public static MapKeyDemo provideInstance(
      Provider<String> paramProvider, Provider<Map<Bar, Integer>> mapProvider) {
    MapKeyDemo instance = new MapKeyDemo(paramProvider.get());
    MapKeyDemo_MembersInjector.injectMap(instance, mapProvider.get());
    return instance;
  }

  public static MapKeyDemo_Factory create(
      Provider<String> paramProvider, Provider<Map<Bar, Integer>> mapProvider) {
    return new MapKeyDemo_Factory(paramProvider, mapProvider);
  }

  public static MapKeyDemo newMapKeyDemo(String param) {
    return new MapKeyDemo(param);
  }
}

@Generated(
  value = "dagger.internal.codegen.ComponentProcessor",
  comments = "https://google.github.io/dagger"
)
public final class MapKeyDemo_MembersInjector implements MembersInjector<MapKeyDemo> {
  private final Provider<Map<Bar, Integer>> mapProvider;

  public MapKeyDemo_MembersInjector(Provider<Map<Bar, Integer>> mapProvider) {
    this.mapProvider = mapProvider;
  }

  public static MembersInjector<MapKeyDemo> create(Provider<Map<Bar, Integer>> mapProvider) {
    return new MapKeyDemo_MembersInjector(mapProvider);
  }

  @Override
  public void injectMembers(MapKeyDemo instance) {
    injectMap(instance, mapProvider.get());
  }

  public static void injectMap(MapKeyDemo instance, Map<Bar, Integer> map) {
    instance.map = map;
  }
}

@Subcomponent

Subcomponent可以使用Component提供的依赖,因此一些公共的组件信息可以由Component提供。

Component和Module

@Module
public class MyModule {
    @Provides
    public MyService provideMyService(){
        return new MyService();
    }
}

@Component(modules = MyModule.class)
public interface MyComponent {
    //添加Subcomponent
    MySubComponent plus(MySubModule mySubModule);
}

Subcomponent和它的Module

@Module
public class MySubModule {
}
@Subcomponent(modules = MySubModule.class)
public interface MySubComponent {
    void inject(SubcomponentDemo demo);
}

注意MyService是在MyModule中提供的而不是MySubModule提供的
使用

public class SubcomponentDemo {

    @Inject
    MyService myService;

    SubcomponentDemo() {
    }
    public static void main(String[] args) {
       SubcomponentDemo demo = new SubcomponentDemo();
        DaggerMyComponent
                .builder()
                .build()
                .plus(new MySubModule())//向Component中添加SubComponent,并返回SubComponent
                .inject(demo);//注入依赖
        demo.myService.serve();//成功注入,说明subcomponent可以使用component提供依赖
    }
}

看一下生成的Component源码

public final class DaggerMyComponent implements MyComponent {
  private MyModule myModule;

  private DaggerMyComponent(Builder builder) {
    initialize(builder);
  }

  public static Builder builder() {
    return new Builder();
  }

  public static MyComponent create() {
    return new Builder().build();
  }

  @SuppressWarnings("unchecked")
  private void initialize(final Builder builder) {
    this.myModule = builder.myModule;
  }

  @Override
  public MySubComponent plus(MySubModule mySubModule) {
    return new MySubComponentImpl(mySubModule);
  }

  public static final class Builder {
    private MyModule myModule;

    private Builder() {}

    public MyComponent build() {
      if (myModule == null) {
        this.myModule = new MyModule();
      }
      return new DaggerMyComponent(this);
    }

    public Builder myModule(MyModule myModule) {
      this.myModule = Preconditions.checkNotNull(myModule);
      return this;
    }
  }
  /**
    * Subcomponent以内部类形式存在于Component类中
    */
  private final class MySubComponentImpl implements MySubComponent {
    private MySubComponentImpl(MySubModule mySubModule) {}

    @Override
    public void inject(SubcomponentDemo demo) {
      injectSubcomponentDemo(demo);
    }

    @CanIgnoreReturnValue
    private SubcomponentDemo injectSubcomponentDemo(SubcomponentDemo instance) {
      SubcomponentDemo_MembersInjector.injectMyService(
          instance,
          MyModule_ProvideMyServiceFactory.proxyProvideMyService(DaggerMyComponent.this.myModule));
      return instance;
    }
  }
}

可以看到 Subcomponent以内部类形式存在于Component类中

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,233评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,013评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,030评论 0 241
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,827评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,221评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,542评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,814评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,513评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,225评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,497评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,998评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,342评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,986评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,812评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,560评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,461评论 2 266

推荐阅读更多精彩内容