Dagger2 (2)

@Qualifier(限定符) 、 @Named

场景:假如在去仓库中寻找Fruit 实例的时候有两个@Provides ,并且return 的东西都是Fruit ,这个时候如果没有做好标识,那么就会出现异常:

![](6.png](http://upload-images.jianshu.io/upload_images/2304809-114089c99fa5e121.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

这个时候就要用到限定符。
@Named是@Qualifier 的一个默认实现。推荐使用@Qualifier。
用法(以下代码都是基于第一篇中的。):
1.新建两个注解类:

@Qualifier
public @interface FruitApple {
    
}
@Qualifier
public @interface FruitPlum {

}

2.在FruitModule 中使用自定义的注解进行标识。

@Module
public class FruitModule {

    @FruitApple
    @Provides
    public Fruit getApple() {
        return new Apple();
    }
    @FruitPlum
    @Provides
    public Fruit getPlum(){
        return  new Plum() ;
    }
}

3 . Fish 中也要指定Fruit 参数前指定注解。

public class Fish {
    private Vegetables vegetables;
    private Fruit fruit;

    @Inject
    Fish(Vegetables vegetables, @FruitApple Fruit fruit) {
        this.vegetables = vegetables;
        this.fruit = fruit;
    }

    public  String getMaterialName(){
      return vegetables.getName()+"-->"+ fruit.getName();

    }
}

@Component下的 dependence 和@SubComponent

dependence 和 @SubComponent的使用:
1.如果想保持两个Component相对独立,并且想明确的显示两个Component之间的依赖关系,就用dependence

dependence eg:

还是上一个的例子(其他类不做改变)。假如Fish是来自第三方类库的(我们无法操作构造函数)。并且的我的Fruit和Vegetables 在其他类中也要声明实例(就是也要用单独的Component),那么我么们直接用dependencies 来之间建立Component之间的依赖关系,而不需要在重复指定modules了。如下

@Component(modules = FruitModule.class)
public interface FruitComponent {
   @FruitApple Fruit getFruit();
}
@Component(modules = VegetablesModule.class)
public interface VegetableComponent {
  //名字和inject 区分
  Vegetables  getVegetable();
}

然后在FishComponent 中建立依赖

@Component(modules =FishModule.class,dependencies = {FruitComponent.class,VegetableComponent.class})
public interface FishComponent {
   //将实例注入目标
   void inject(MainActivity mainActivity);
}

MainActivity 中完成注入。

 DaggerFishComponent.builder()
                .fishModule(new FishModule())
                .fruitComponent(DaggerFruitComponent.create())
                .vegetableComponent(DaggerVegetableComponent.create())
                .build().inject(this);
@SubComponent eg:

@SubComponent 作用更加偏向于: A Component 只为B Component 才提供作用的,而自己本身并没有其他的独立作用,代码上也是只有在拿到A Component的时候才能拿到BComponent。 (就是A和B是紧密结合的),并且B Component 也不关心依赖着哪一个Component

  1. 其他的不变,只要改动Component
@Component(modules = FruitModule.class)
public interface FruitComponent {
   VegetableComponent getVegetableComponent(VegetablesModule vegetablesModule);
}
@Subcomponent(modules = VegetablesModule.class)
//身为Subcomponent的我,并不知道我依赖着哪一个Component
public interface VegetableComponent {

   FishComponent getFishComponet(FishModule fishModule);
}
@Subcomponent(modules = FishModule.class)
public interface FishComponent {
   //将实例注入目标
   void inject(MainActivity mainActivity);
}
  1. mainActivity 注入。
 DaggerFruitComponent.create()
                .getVegetableComponent(new VegetablesModule())
                .getFishComponet(new FishModule())
                .inject(this);

@Scope(限定域)和@Singleton

这个地方起始还是有点坑的。
@Singleton : 披着全局单例的皮,起始它并没有全局单例的能力。(能力和自定义的@Scope是一样,他只是事先定义好的。)

@Scope
@Documented
@Retention(RUNTIME)
public @interface Singleton {}

看看就知道(还是上面的例子):

1.先来和所有@Scope一样的用法(再@provides 和 @Component 加上@Singleton):

@Module
public class FishModule {
    @Provides
    @Singleton
    public Fish getFish(Vegetables vegetables, @FruitApple Fruit fruit){
        return new Fish(vegetables,fruit);
    }
}

多增加一个Activity(用于测试是否全局单例)

@Singleton
@Component(modules = FishModule.class,dependencies = {FruitComponent.class,VegetableComponent.class})
public interface FishComponent {
   //将实例注入目标
   void inject(MainActivity mainActivity);

   void inject(TestActivity testActivity);
}

再MainActivity 中测试两条鱼是否一样。

public class MainActivity extends AppCompatActivity {
// Activity  如有多个不同类的实例需要注入,那么也要在一个Component注入。
//不能使用多个Component。
    @Inject
    Fish fish;
    @Inject
    Fish fish2;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerFishComponent.builder().vegetableComponent(DaggerVegetableComponent.create())
                .fruitComponent(DaggerFruitComponent.create()).build().inject(this);

        Button btn= (Button) findViewById(R.id.resultBtn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(MainActivity.this,TestActivity.class));
            }
        });
        Log.e("TAG","------------------->"+fish);
        Log.e("TAG","------------------->"+fish2);
        //=====结果 :true========
        btn.setText((fish==fish2)+"");
    }
public class TestActivity extends AppCompatActivity {

    @Inject
    Fish fish3;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        DaggerFishComponent.builder().vegetableComponent(DaggerVegetableComponent.create())
                .fruitComponent(DaggerFruitComponent.create()).build().inject(this);

        Log.e("TAG","------------------->"+fish3);
    }
}

![

B9%$~W2FZ`V{HOPD`I~MQV3.png

]SKU]2GLEG]93.png](http://upload-images.jianshu.io/upload_images/2304809-099eddf1370045aa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

可见只有在同一个DaggerFishComponent的实例之下,注入的Fish 才是一样的。

那为什么说他披着全局的皮呢?

Dagger 2也是建议将@Singleton 用于全局。而自定义@Scope用于局部。
1.代码的可读性。@Singleton 给人以看就可以知道是单例的。而那些常用的自定义@ActivityScope @FragmentScope (这是要自己声明的) 则是侧重于作用于Activity、Fragment范围内。便于可读,分别开来。
2。侧面说明:其他的@Scope 可以依赖于@Singleton。但是@Singleton 依赖于其他的@Scope编译上就会报错。Dagger2 也说它是生命周期最长的,生命周期长的无法以依赖于短的。(说明@Singleton得天独厚。哈哈。)

那么怎么获取全局单例?

只需要保证获取到的FishComponent是一样的。那么就将FishComponent的获取放在Application中,那个Activity要用,先先getApplication,再去获取唯一的FishComponent即可。

修改一下:
1.自定义一个@Scope

@Scope
public @interface ActivityScope {
}

2.给FishComponent、FishModule 注解

@ActivityScope
@Component(modules = FishModule.class,dependencies = {FruitComponent.class,VegetableComponent.class})
public interface FishComponent {
   //将实例注入目标
   void inject(MainActivity mainActivity);

   void inject(TestActivity testActivity);
}

@Module
public class FishModule {
    @ActivityScope
    @Provides
    public Fish getFish(Vegetables vegetables, @FruitApple Fruit fruit){
        return new Fish(vegetables,fruit);
    }
}

3 创建 AppComponent、AppModule

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {

    void inject(MyApp myApp);
}

@Module
public class AppModule {

    @Provides
    @Singleton
    public  FishComponent  getFishCompent(){
       return DaggerFishComponent.builder().vegetableComponent(DaggerVegetableComponent.create())
                .fruitComponent(DaggerFruitComponent.create()).build();
    }
}

4 application 注入

public class MyApp extends Application {
    @Inject
    FishComponent fishComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        DaggerAppComponent.create().inject(this);
    }

    //
    public FishComponent getFishComponent(){
        return  fishComponent;
    }
}

5 Activity 中测试是否单例

public class MainActivity extends AppCompatActivity {
    @Inject
    Fish fish;
    @Inject
    Fish fish2;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ((MyApp) getApplication()).getFishComponent().inject(this);
        Log.e("TAG","------------------->"+fish);
        Log.e("TAG","------------------->"+fish2);
    }
}

public class TestActivity extends AppCompatActivity {

    @Inject
    Fish fish3;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ((MyApp) getApplication()).getFishComponent().inject(this);
        Log.e("TAG","------------------->"+fish3);
    }
}

输出的地址就是一样的了(不贴了)。
@Scope 跟最上面测试@Singleton一样的用法。我们一般是用来的定义局部的。

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

推荐阅读更多精彩内容