Android Dagger2 从零单排(二) @Qualifier

  转发请注明出处:https://www.jianshu.com/p/b35a658bb1ba
  Dagger2作为Android界最具杀伤力的匕首,本系列文章将用最通俗的语言带领你揭开它的真面目。
  边缘OB:从零单排带你从低分局打到高分局,从First Blood(第一滴血)到Holy Shit(超越神的杀戮),每盘Rampage(暴走)不在话下!
  Android Dagger2 从零单排(一) 基础注解
  Android Dagger2 从零单排(二) @Qualifier
  Android Dagger2 从零单排(三) @Scope
  Android Dagger2 从零单排(四) Dependencies与SubComponent

  在上一篇文章里面,我们介绍了Dagger2最基本的使用以及每个注解的作用,我们用上一篇留下的问题作为开篇:多个构造方法想要@Inject、多个@Provides方法返回同一数据类型,这种情况该如何注入?
  我们来介绍另外一个注解:@Qualifier
  我们称其为限定标识符,只能用于注解上。通俗点说,就是我们使用这个注解,自定义一个标识符注解来给我们所要区分的依赖打上记号,让Dagger2通过记号来获取依赖。
  例子一,没错,还是最简单的例子,还是领导视察民情,小秘上回告诉车场调度员要请个司机,隔壁老王又是车场调度员的关系户,如何才能让隔壁老王如愿以偿呢。
  我们先来定义一个标识符注解,注解类型使用@interface关键字:

@Qualifier
public @interface Sign {
}

  此时使用了@Qualifier创建了一个标识符注解@Sign,注意,不能注解在构造方法中,所以多构造方法与多个@Provides方法返回同一数据类型的处理方式是一样的,然后我们在例子中使用@Sign:

public class Bus {
    private String driver;
    public Bus() {
    }
    public Bus(String driver) {
        this.driver = driver;
    }
}

public class ParkingActivity extends Activity {
    @Sign
    @Inject
    Bus mBus;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_dagger);
        DaggerParkingComponent.create().inject(this);//DaggerParkingComponent类需要编译才会生成
        ((TextView) findViewById(R.id.text)).setText("属性注入成功 = " + mBus.toString());//重写Bus的toString()方法能看到打印出"隔壁老王",注入成功
    }
}

@Component(modules = ParkingModule.class)
public interface ParkingComponent {
    void inject(ParkingActivity activity);
}

@Module
public class ParkingModule {
    @Provides
    public Bus provideBus() {
        return new Bus();
    }
    @Sign
    @Provides
    public Bus provideBusHasDriver() {
        return new Bus("隔壁老王");
    }
}

  在例子中可以看到,我们在要注解的属性mBus与提供依赖的方法provideBusHasDriver上各添加了一个注解@Sign,此时mBus有了标识,Dagger2只会提供对应标识的依赖,然后注入,如果把mBus的@Sign注释取消,Dagger2就会通过provideBus方法注入Bus。
  如果Bus的构造方法再加几个,此时又如何区分呢?其实,标识符也可以有自己的成员变量。(实际上是一个成员方法,说成员变量是为了方便理解)

@Qualifier
public @interface Sign {
    String value() default "";
}

  我们可以看成定义了一个String 类型的value成员变量,其默认值是空字符串,然后我们改变下@Sign的写法:

public class ParkingActivity extends Activity {
    @Sign("laoWang")
    @Inject
    Bus mBus;
    ...
}

@Module
public class ParkingModule {
    @Sign("noDriver")
    @Provides
    public Bus provideBus() {
        return new Bus();
    }
    @Sign("laoWang")
    @Provides
    public Bus provideBusHasDriver() {
        return new Bus("隔壁老王");
    }
}

  因为注入的mBus有@Sign("laoWang")标识,Dagger2只会选择老王为司机的车注入,哪天不想要老王了,只需要改变@Sign里面的字符串即可马上把老王踢了。
  对于这个成员变量,我有话要说:
  1.咋一看有没有纠结为什么要写成value?其实你想写啥就写啥,不过,使用value有个好处就是可以不用写属性名直接指定值,例如把value改成driver:

@Qualifier
public @interface Sign {
    String driver() default "";
}

@Sign(driver = "laoWang")

  2.能不能不设置默认值?能!每次使用的时候请为其指定值,否则报错,设置了默认值之后,使用时注解不指定值时,使用的是默认值。
  3.能加参数么?不能!只能以无形参的方法形式来声明。
  4.能不能有多个成员变量?能!多个成员变量并非要全部使用:

@Qualifier
public @interface Sign {
    String value() default "";
    String value2() default "";
}

@Sign("laoWang")//此时只使用了默认的value一个属性
@Sign(value2 = "laoLi")//此时只使用了value2一个属性
@Sign(value = "laoWang", value2 = "laoWang")//此时只使用了两个属性

  5.数据类型有没有要求?有!只能是基本数据类型、String、Enum、Class,包含其一维数组类型。
  例子二,其他情况的应用。
  (1)方法注入的应用:

    @Inject
    public void injectBus(@Sign("laoWang") Bus bus) {
        mBus = bus;
    }

  此时@Sign不能注解在方法上,必须注解在对应的注入参数中。
  (2)@Provides方法依赖关系的应用:

    @Sign("laoWang")
    @Provides
    public Bus provideBusHasDriver(@Sign("lw") String driver) {
        return new Bus(driver);
    }

    @Sign("lw")
    @Provides
    public String provideDriverW() {
        return "隔壁老王";
    }

  总结:
  标识符具有对应性,在需要依赖注入的地方有标识,则在提供依赖的地方也一定要有,否则报错。(不要跟我说,可以在提供的依赖注解标识,但是需要依赖注入的地方不注解标识,你看明明也正确,但对应不上!......我会打你的!)
  标识符的值具有唯一性,其实正确来说只能是相对唯一性,例子一中ParkingModule的提供Bus依赖的@Provides方法,@Sign都必须是唯一的,存在相同的情况则编译报错(除非你写了两个相同的@Sign提供依赖,但压根都没用到,这时候编译也不会报错也能运行,Dagger2机制不使用的自然不会监测!......但是我还是会打你的!),而依赖注入的地方则不受限制。另外这个唯一性,只是对同一返回类型。例如在例子二@Provides方法依赖关系的应用中,我们把@Sign("lw")同样也写成@Sign("laoWang"),是完全没问题的。

  最后我想说,有一个现成的限定标识符是可以直接使用的:@Named

@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Named {
    String value() default "";
}

  比起我们的例子,多了两个注解@Documented和@Retention(RUNTIME)。
  @Documented官方解释是文档化,如果一个类型的声明是用Documented来注解的,则其注解将成为注解元素的公共API的一部分,其实没有什么卵用,加不加都可以。
  @Retention(RetentionPolicy.RUNTIME)这个注解到现在我还没研究出来到底要不要加,加的话给什么属性,我用上面的例子仔细的研究了Dagger2编译过后生成的所有类(这些原理后面会有介绍),发现没有任何关于@Sign的生成类或者注释说明,为此我大胆猜测,@Qualifier标识符注解其实是在编译期间有用,是作为指引依赖之间的关联而存在的,运行时依赖注入与被依赖注入间的关系已经由Dagger2生成的类定义好,所以我觉得这个@Retention添加不添加没啥区别,不添加的情况,其默认是RetentionPolicy.CLASS,如果有误的话,欢迎留言指正。

  Demo源码截我 对应daggerTwo包名
  Dagger2 GitHub地址
  Dagger2 官网地址
  所有的测试实例均基于2.15版本。
  下一篇,我们来研究作用域:@Scope注解。

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

推荐阅读更多精彩内容

  •   转发请注明出处:https://www.jianshu.com/p/7ee1a1100fab  Dagger2...
    MrTangFB阅读 5,993评论 11 45
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,568评论 25 707
  • Dagger2 入门 2016-12-21 更新:添加@Subcomponent注解以及Lazy与Provider...
    fxzou阅读 28,462评论 77 331
  • 标签(空格分隔): 前端 Webpack 是当下最热门的前端资源模块化管理和打包工具。它可以将许多松散的模块按照依...
    ahcj_11阅读 255评论 0 1
  • 昨天给一个乌克兰小妹妹开银行卡,高鼻深目,皮肤白皙,传统的乌克兰美女长相,一起来的还有一个外国美女和一个翻译,因为...
    喂喂喂无羡阅读 146评论 0 0