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一样的用法。我们一般是用来的定义局部的。

你可能感兴趣的:(Dagger2 (2))