Dagger2 入门晋级篇,直奔主题吧!
一 :组件之间的依赖
- MainActivityModule 中Schoole的提供方法,需要参数Principal 的实例,但是MainActivityModule ,中并没有提供。可是AppComponent对应的AppModule有提供。于是我们让MainComponent依赖AppComponent,并在AppComponent中将Principal 实例提供出来。另外注入的时候也略有不同,具体看代码(提示:这些代码在Demo中的simplemvpmedo 的Module中哦)
@(个人博客)Module
public class MainActivityModule {
private MainActivity mMainActivity;
public MainActivityModule(MainActivity activity) {
this.mMainActivity = activity;
}
//货架
@Provides
public MainActivity provideMainActivity() {
return mMainActivity;//货架提供的商品
}
@Provides
public Schoole provideSchoole(Principal principal) {
return new Schoole(principal);
}
}
MainActivityModule 相对应的MainComponent ,该MainComponent 依赖了AppComponent。然后我们在看下AppComponentded
/**
* Created by zyg on 2016/11/8.
* 供货商,交易商
*/
@Component(dependencies = AppComponent.class ,modules = MainActivityModule.class)
public interface MainComponent {
void inject(MainActivity mainActivity);//签订合同,必须用MainActivity(采购商),接收。它老爸都不行哦
}
- AppComponent 作为被依赖的控件,需要向依赖它的控件提供Principal 的实例,因为依赖它的组件MainComponent 需要Principal 的实例,然后再看AppComponent 对应的Module
@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
void inject(MyApplication application);
//父组件必须把该类的实例提供给子组件
Principal getPrincipal();
}
- 调用的时候也有区别,还是看代码,看看注入代码
public class MainActivity extends AppCompatActivity {
private static final String TAG = "daggerTest";
@Inject
Schoole mSchoole;
@Inject
Schoole mSchoole2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainComponent.builder()
.appComponent(getComponent())
.mainActivityModule(new MainActivityModule(this))
.build()
.inject(this);
}
//获取AppComponent
private AppComponent getComponent() {
return ((MyApplication) getApplication()).getAppComponent();
}
//更新UI的操作
public void refeshUi() {
Log.d(TAG, "更新ui");
}
}
- 注入的时候多了appComponent(),这个方法,需要传入AppComponent作为参数,这里我们从MyApplication中获取,看下MyApplication 的代码
public class MyApplication extends Application {
@Inject
Principal mPrincipal; //校长
@Inject
Principal vicePrincipal;//副校长
AppComponent appComponent;
@Override
public void onCreate() {
appComponent = DaggerAppComponent
.builder()
.appModule(new AppModule())
.build();
appComponent.inject(this);
Toast.makeText(this, mPrincipal.say(), Toast.LENGTH_SHORT).show();
}
public AppComponent getAppComponent() {
return appComponent;
}
}
总结:这样MainComponent 就从AppComponent中拿到了Principal 的实例,并传给new Schoole方法,最终完成 Schoole类的实例注入到MainActivity的任务。提醒下AppComponent,一定得把Principal 提供出去,这是关键。
二: @SubComponent,子组件(公共组件)
- 如果有一个组件,是每次创建实例提供给别人,而恰好其他组件(有多个)里面有需要它,如果只有一个,我们就用依赖搞定啦。多个它就可以定义成子组件,谁需要在谁的组件里面加一下,具体看例子.(提示:Demo源码中的DaggerTest的Module哦)
- 先来定义个子组件,注解@Subcomponent.
@PerActivity
@Subcomponent(modules = ComonModule.class)
public interface CommonComponent {
Test4 getText4();
}
- 在看与子组件相关的Module--ComonModule ,子组件提供Test4,Test4的代码就不贴了,在Demo中看吧。
@Module
public class ComonModule {
@Provides
public Test4 provideTest4() {
return new Test4();
}
}
- 再看父组件ApplicationComponent ,定义个抽象方法getCommonComponent(),把该子组件提供出去。需要用到该子组件的组件都要提供这么一个抽象方法,把子组件提供出去。
@PerActivity
@Component(modules = AndroidModule.class)
public interface ApplicationComponent {
void inject(DemoApplication application);
LocationManager getLocationManager();
CommonComponent getCommonComponent();
}
- 父组件的Module-- *AndroidModule *
@Module
public class AndroidModule {
private final DemoApplication application;
public AndroidModule(DemoApplication application) {
this.application = application;
}
@Provides
@PerActivity
public LocationManager provideLoctionManager() {
return (LocationManager) application.getSystemService(LOCATION_SERVICE);
}
}
- 注入到DemoApplication中,先 调用ApplicationComponent 的getCommonComponent()方法,得到子组件,然后调用子组件的 getText4()方法,得到Text4的实例, 具体看代码
public class DemoApplication extends Application {
@Inject
LocationManager locationManager;
private ApplicationComponent component;
@Override
public void onCreate() {
super.onCreate();
component = DaggerApplicationComponent.builder()
.androidModule(new AndroidModule(this))
.build();
/* //Component0中用单例注解,Module中也用单例注解,并且只获取一个子Component,则可以保持单例
CommonComponent commonComponent = component().getCommonComponent();
Test4 test4 = commonComponent.getText4();
Test4 test41 = commonComponent.getText4();*/
//这种写法,即使Component中,Module中都用了单例注解,也无法实现单例
Test4 test4 = component.getCommonComponent().getText4();
Test4 test41 = component.getCommonComponent().getText4();
component().inject(this);
Toast.makeText(this, locationManager.getClass().getSimpleName(), Toast.LENGTH_SHORT).show();
}
public ApplicationComponent component() {
return component;
}
}
子组件的总结:
- 子组件不能独立使用,必须依靠父组件才能向外提供实例。
- 父组件必须提供抽象方法,将该子组件提供出去。然后才能拿到子组件,并获取子组件提供的类的实例。
三:单例的使用@Scope注解;
- 如何实现单例,依然是看代码
- AppModule的代码:
import com.zhang.testing.simplemvpdemo.bean.Principal;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
/**
* Created by zyg on 2016/11/15.
*/
@Module
public class AppModule {
@Provides
@Singleton
public Principal providePrinciple() {
return new Principal();
}
}
- AppComponent的代码
package com.zhang.testing.simplemvpdemo.di.component;
import com.zhang.testing.simplemvpdemo.MyApplication;
import com.zhang.testing.simplemvpdemo.di.module.AppModule;
import javax.inject.Singleton;
import dagger.Component;
/**
* Created by zyg on 2016/11/15.
*/
@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
void inject(MyApplication application);
}
注入代码就不贴了,看效果,实现了单例。那么如何实现单例??
- 就是Module 中和 Component中都用@Singleton,注解(注意Module中应该注解在提供方法哪里),即必须成对出现才能实现单例
- 如果Module 中没有注解,Component中可注解,可不注解,但是Module中提供了注解,Component中必须提供注解,否则编译无法通过,必须成对出现才能实现单例哦!重要事情说两遍了!!!
- 如果某个类是用@Inject注解,为Component提供实例的,那么无法在该类内使用注解实现单例,只能在Module中的Provide方法里使用注解实现单例
2. 那么你要问了@Singleton,是神马??,其实@Singleton,只是Dagger2为给我们提供的默认单例注解,其实它靠的还是@Scope, 越来越糊涂了??有木有?不着急马上就会豁然开朗!看下@Singleton的代码
@Scope
@Documented
@Retention(RUNTIME)
public @interface Singleton {}
看到了吗?@Singleton里面有个@Scope的注解。现在还不是解释的时候。那我们也写个像@Singleton的注解,看看能不能用。我们自定义了个@OnlyInstance ,然后我们把上面代码的 AppComponent和AppModule中的@Singleton,全部替换为@OnlyInstance ,运行后发现和用@Singleton的效果一摸一样,同样实现了单例。那么说明了什么呢?
@Retention(RUNTIME)
@Scope
public @interface OnlyInstance {
}
- 我们自定义的注解@OnlyInstance 和Dagger2提供的注解@Singleton,效果相同。他们都能实现单例,因为中间都有@Scope这个注解。
- @Scope 是个能提供局部单例的注解,这个注释的意思就是作用域,在作用域内保持单例,同属于一个作用域,共用一个相同实例。这会与component的生命周期(不是整个应用)关联.只是Component的生命周期内哦!有了它我们就能自定义很多个可以提供单例的注解。为什么需要自定义很多个注解??
- 因为各个组件Component要独立出来,而要独立出来就不能在同一个作用域,那么就不能使用同一个注解.当然如果两个不相关的Component之间,可以用相同的注解。
- 但是如果两个Component是依赖关系则不能用相同的单例注解。
- 那么问题来了,我们说@Scope,能让实例在Component生命周期内保持单例,那如果我想全局保持单例,与整个应用的生命周期一样,那么该怎么做呢?其实我们在上面说依赖的时候已经贴过代码,只是没有详细的去解释而已。
- Test3注入MainActivity中需要传入参数LocationManager的实例,但是MainActivityComponent对应Module中并没有提供这个实例,那么只能依赖ApplicationComponent。先看Test3的代码
public class Test3 {
private LocationManager locationManager;
public Test3(LocationManager manager) {
this.locationManager = manager;
}
public String sayName(){
return "我是Test3";
}
}
父组件的代码,注意这里用的单例注解是 @PerActivity
@PerActivity//当Module中使用了单例注解,Component中必须使用单例注解。
@Component(modules = AndroidModule.class)
public interface ApplicationComponent {
void inject(DemoApplication application);
LocationManager getLocationManager();//将LocationManager 提供给子控件
}
父组件对应的Module,注意这里用的单例注解是 @PerActivity
@Module
public class AndroidModule {
private final DemoApplication application;
public AndroidModule(DemoApplication application) {
this.application = application;
}
@Provides
@PerActivity// 这是自定义单例注解
public LocationManager provideLoctionManager() {
return (LocationManager) application.getSystemService(LOCATION_SERVICE);
}
}
在看子组件的代码注意这里的单例注解我们用的是@OnlyInstance,和父组件的不一样,如果一样会报错。
@OnlyInstance
@Component(dependencies = ApplicationComponent.class,modules = CModule.class)
public interface MainActivityComponent {
void inject(MainActivity activity);
}
在看看与子控件相关的Module代码,这里Module我们并没有让Test3也是单例状态,所以Test3的注入不是单例的。但是我们的目的是看LocationManager 注入是不是单例的。
@Module
public class CModule {
@Provides
Test3 provdeText3(LocationManager locationManager){
return new Test3(locationManager);
}
/**
* 依赖中单例的总结:
* 单例有源头性,如果上游是单例接收必须单例。
* 父类Component提供的是单例,子Component必须单例,
* 但仅限于Component,子的Module不受影响
* Component 和Module之间,Module 是单例,Component必须单例。
* @Scope的一个注释,这个注释的意思就是作用域,
* 在作用域内保持单例:同属于一个作用域,共用一个相同实例
* 为什么要新增一个呢,因为各个组件需要独立出来,
* 因此如果是依赖关系,则需要各自在不同的注释作用域里面
* (所以自定义一个@OnlyInstance)
* 子Component 和 父Component 作用域不能相同,必须各自在不同的作用域里
* 但是 Component和 Module之间必须用相同的作用域,当然如果Module没有,Component就随意了
* 然后我们又定义了一个@PerActivity
* 我们将之前的@Singleton用新建的(自定义的@PerActivity)替换掉,
* 验证两次的生成代码,发现一模一样,
* @Singleton,只是Dagger2为我们提供的一个单例注解。我们可以根据自己的需求自定义自己的单例注解
* 但是我们定义的时候要命名最好是有意义的,@PerActivity,我们希望它的作用是保持Activity内单例,见名知意吧!
*
* */
}
接下来我们再看下注入代码。这里applicationComponent,方法需要的参数applicationComponent的实例,我们是从DemoApplication中获取的。只有保证了applicationComponent的唯一性才能保证单例超出Component生命周期后依然有效。这也变相说明@Scope注解实现了Component内单例,与Component生命周期相关,而不是与整个应用生命周期相关。
public class MainActivity extends AppCompatActivity {
@Inject
Test3 test3;
@Inject
Test3 test2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main)
DaggerMainActivityComponent.builder()
.applicationComponent(((DemoApplication) getApplication()).component())
.build()//applicationComponent方法需要的参数是从DemoApplication获取的,没有重新新建
.inject(this);
Toast.makeText(this, test2.sayName(), Toast.LENGTH_SHORT).show();
}
}
然后我们看下效果图
- 子组件提供的类的实例无法通过注解的方式直接实现单例,但是我们可以通过只获取一个子组件Component而实现单例。而且子组件和父组件可以使用相同的单例注解。具体看代码吧!
- 子组件的代码
@PerActivity
@Subcomponent(modules = ComonModule.class)
public interface CommonComponent {
Test4 getText4();
}
子组件相对应的Module
@Module
public class ComonModule {
@PerActivity
@Provides
public Test4 provideTest4() {
return new Test4();
}
}
调用时候只获取一个子Component,就能实现单例,代码如下
public class DemoApplication extends Application {
private ApplicationComponent component;
@Override
public void onCreate() {
super.onCreate();
component = DaggerApplicationComponent.builder()
.androidModule(new AndroidModule(this))
.build();
CommonComponent commonComponent = component().getCommonComponent();
Test4 test4 = commonComponent.getText4();
Test4 test41 = commonComponent.getText4();
component().inject(this);
Toast.makeText(this, locationManager.getClass().getSimpleName(), Toast.LENGTH_SHORT).show();
}
public ApplicationComponent component() {
return component;
}
}
单例的总结:我们自定义单例注解的时候,最好每个自定义的名称都有意义,比如在Activity内保持单例,那么就定义为@perAcvitity.
四: @Scope是用来自定义单例注解的,那么还有没有其他的,可以自定义的呢?就喜欢你这好奇的性格,还真有,它就是@Qualifier。它是做什么的呢?看个栗子!
- 假设有这么个类需要注入Test5,当传入的值不同时,它的属性就不同。但是他们都是Test5类,系统如何区分他们呢?他们没办法区分。于是我们就得告诉他们,哪个是哪个。。。。,我们这里先用Dagger2提供的一个注解@Named。它需要传入一个字符串,来区别不同的实例。
public class Test5 {
private int mFlag;
public Test5(int flag) {
this.mFlag = flag;
}
public String signature() {
if (mFlag == 1) {
return "我是美女。。。";
} else if(mFlag==0){
return "我是帅哥";
}else if(mFlag==2){
return "我是男人";
}else {
return "我是女人";
}
}
}
- 接着来看Module 里面怎么写的。
@Module
public class AndroidModule {
private final DemoApplication application;
public AndroidModule(DemoApplication application) {
this.application = application;
}
@Provides
@PerActivity
public LocationManager provideLoctionManager() {
return (LocationManager) application.getSystemService(LOCATION_SERVICE);
}
@PerActivity
@Provides
public Context provideContext() {
return application.getApplicationContext();
}
@PerActivity
@Provides
@Named("boy")
public Test5 provideBoy() {
return new Test5(0);
}
@PerActivity
@Provides
@Named("girl")
public Test5 provideGirle() {
return new Test5(1);
}
}
- 在看看怎么注入的,注入的时候也要注解清楚,不然系统还是无法区分他们的。这样就完成注入了。
public class DemoApplication extends Application {
@Inject
@Named("boy")
Test5 boy;
@Inject
@Named("girl")
Test5 girl;
private ApplicationComponent component;
@Override
public void onCreate() {
super.onCreate();
component = DaggerApplicationComponent.builder()
.androidModule(new AndroidModule(this))
.build();
/* //Component0中用单例注解,Module中也用单例注解,并且只获取一个子Component,则可以保持单例
CommonComponent commonComponent = component().getCommonComponent();
Test4 test4 = commonComponent.getText4();
Test4 test41 = commonComponent.getText4();*/
//这种写法,即使Component中,Module中都用了单例注解,也无法实现单例
Test4 test4 = component.getCommonComponent().getText4();
Test4 test41 = component.getCommonComponent().getText4();
component().inject(this);
Toast.makeText(this, locationManager.getClass().getSimpleName(), Toast.LENGTH_SHORT).show();
}
public ApplicationComponent component() {
return component;
}
}
- 等等,我们不是说自定义注解的吗?是的,@Name(xx),是Dagger2提供的注解。我们看看它的代码。
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Named {
/** The name. */
String value() default "";
}
- 我们自定义个几个试一试
男孩
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface ForBoy {
}
女孩
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface ForGirl {
}
- 然后我们用下试一试,直接上代码了哦!首先Module类,这里为了和原来的@Name区分开来,我把他们叫做男的和女的
@Module
public class AndroidModule {
private final DemoApplication application;
public AndroidModule(DemoApplication application) {
this.application = application;
}
@Provides
@PerActivity
public LocationManager provideLoctionManager() {
return (LocationManager) application.getSystemService(LOCATION_SERVICE);
}
@PerActivity
@Provides
public Context provideContext() {
return application.getApplicationContext();
}
@PerActivity
@Provides
@Named("boy")//Dagger2提供的默认注解
public Test5 provideBoy() {
return new Test5(0);
}
@PerActivity
@Provides
@Named("girl")
public Test5 provideGirle() {
return new Test5(1);
}
@PerActivity
@Provides
@ForBoy//因传入的值不相同,所以属性不相同,而Dagger2无法区分,我们用注解告诉系统,他们是不同的,有区别的,
public Test5 provideMan(){//因为Dagger2是以返回的类的名称来区分不同的返回方法的。
return new Test5(2);
}
@PerActivity
@Provides
@ForGirl//我们自定义的注解
public Test5 provideWoman(){
return new Test5(3);
}
}
再看注入的地方。
public class DemoApplication extends Application {
@Inject
LocationManager locationManager;
@Inject
@Named("boy")//注入到的地方也要有相应的注解,否则Dagger2还是无法区分的
Test5 boy;
@Inject
@Named("girl")
Test5 girl;
@Inject
@ForBoy//自定义的注解
Test5 man;
@Inject
@ForGirl
Test5 woman;
private ApplicationComponent component;
@Override
public void onCreate() {
super.onCreate();
component = DaggerApplicationComponent.builder()
.androidModule(new AndroidModule(this))
.build();
/* //Component0中用单例注解,Module中也用单例注解,并且只获取一个子Component,则可以保持单例
CommonComponent commonComponent = component().getCommonComponent();
Test4 test4 = commonComponent.getText4();
Test4 test41 = commonComponent.getText4();*/
//这种写法,即使Component中,Module中都用了单例注解,也无法实现单例
Test4 test4 = component.getCommonComponent().getText4();
Test4 test41 = component.getCommonComponent().getText4();
component().inject(this);
Toast.makeText(this, locationManager.getClass().getSimpleName(), Toast.LENGTH_SHORT).show();
}
public ApplicationComponent component() {
return component;
}
}
- 另外,如果我们把boy,girl提供给依赖它的组件,那么提供方法里也要用相应的注解,否则报错的。具体看代码,一看就懂了。
@PerActivity
@Component(modules = AndroidModule.class)
public interface ApplicationComponent {
void inject(DemoApplication application);
LocationManager getLocationManager();
CommonComponent getCommonComponent();
//提供给子组件使用的时候也要有相应的注解。不然怎么分辨呢
@Named("boy")
Test5 provideBoy();
@Named("girl")
Test5 provideGirl();
@ForBoy
Test5 provideMan();
@ForGirl
Test5 provideWoman();
}
就是这么自定义的,至于为什么要自定义,每次敲入不同的字符串你不烦吗?万一敲错了呢?那又怎么办!!
五:懒加载,这个比较简单。
- Component和Module中的写法没任何变化,只是在注入的地方略有不同。用 Lazy<>
把懒加载的类包裹起来,用的时候调用get方法获取类的实例
public class MainActivity extends AppCompatActivity {
@ForGirl
Lazy<Test5> beautifulGirl;//漂亮的女孩都比较懒
//注入的地方懒加载这么写。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main)
DaggerMainActivityComponent.builder()
.applicationComponent(((DemoApplication) getApplication()).component())
.build()
.inject(this);
Toast.makeText(this, beautifulGirl.get().signature(), Toast.LENGTH_SHORT).show();
//注入完成后只是提供一个可以生成Test5的对象,通过get(),才能获得我们需要的真正实例
}
}
六: 多绑定到Set中,一个Component可以有多个Module,同时不同Module中的相同数据类型的元素可以绑定到同一个Set中。这里我们列举了两种类型的Set,Set<String>和Set<Integer>
第一个ModuleA,第一个方法提供Set<String> 元素为:"ABC" ,第二个方法提供了Set<String>元素为:"abc"
第三个方法提供了Set<String>元素为:"DEF", "GHI" ,第四个方法提供了Set<Integer> 元素为:1
@Module
public class ModuleA {
@Provides
@IntoSet
public String provideString(LocationManager locationManager) {
return "ABC";
//注入到Set<String>中,单个元素就用 @IntoSet
}
@Provides
@IntoSet
public String provideSecond(LocationManager locationManager) {
return "abc";
//注入到Set<String>中单个元素就用 @IntoSet
}.
@Provides
@ElementsIntoSet
public Set<String> provideStings(LocationManager manager) {
return new HashSet<String>(Arrays.asList("DEF", "GHI"));
//注入到Set<String>中,列表和多个元素用@ElementsIntoSet
}
@Provides
@IntoSet
public Integer provideInterger(LocationManager locationManager) {
return 1;
//注入到Set<Integer>中
}
/**
* 这里需要注意的就是,在组件里面加入多个绑定的时候,
* module的里面必须要有一个是@IntoSet 这个作为第一个标记,
* 否则会出错,可以多个@IntoSet标记。
如果是列表类型的,则使用@ElementsIntoSet就ok了。
* */
}
ModuleB,这个Module提供了Set<String>的元素为:"def", "ghi" 和 Set<Integer> 元素为:3, 2
@Module
public class ModuleB {
@Provides
@ElementsIntoSet
public Set<String> provideStings(LocationManager manager){
return new HashSet<String>(Arrays.asList("def", "ghi"));
//注入到Set<String>,多个元素用@ElementsIntoSet
}
@Provides
@ElementsIntoSet
public Set<Integer> provideIntegers(LocationManager manager) {
return new HashSet<Integer>(Arrays.asList(3, 2));
//注入到Set<Integer>中,因为是列表型所以 @ElementsIntoSet注解
}
}
MainActivityComponent ,依赖了ApplicationComponent,注意:这里有个抽象方法 Set<String> getStrings();把Set<String> 提供出去的。具体什么用,我们待会说。
@OnlyInstance
@Component(dependencies = ApplicationComponent.class,modules = {ModuleA.class, ModuleB.class})
public interface MainActivityComponent {
void inject(MainActivity activity);
Set<String> getStrings();
}
现在就该到注入环节了。注入方式有两种哦
- 第一种注入方式,我们定义了相应类型的Set,接收注入。
public class MainActivity extends AppCompatActivity {
@Inject
Set<String> mStringSet;//注入的为Set<String>
@Inject
Set<Integer> integerSet;//注入的为 Set<Integer>
@Inject
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainActivityComponent.builder()
.applicationComponent(((DemoApplication) getApplication()).component())
.build()
.inject(this);
}
}
如果我们在Component中移除ModuleB那么ModuleB中提供的相应元素就不会注入到相应Set中了,另外Dagger2会把数据类型相同的都注入到同一个Set中,提供类型为 Set<Integer>注入到integerSet里,提供类型为Set<String>mStringSet中。
- 第二种方式:还记得我们刚在MainActivityComponent 中提醒大家注意的那个抽象方法吗?第二个方法首先就是MainActivityComponent 中得定义一个抽象方法把Set<String>提供出来。这里我们只做个演示。所以就只做个Set<String> 的
public class MainActivity extends AppCompatActivity {
Set<String> mStringSet;//注入的为Set<String>
@Inject
Set<Integer> integerSet;//注入的为 Set<Integer>
@Inject
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mStringSet = DaggerMainActivityComponent
.builder()
.applicationComponent(((DemoApplication) getApplication()).component())
.build()
.getStrings();
}
}
看效果图多绑定到Map中,既然可以绑定到Set那么Map也不例外
首先看MyModule1 ,分别提供了几种类型的Map 同Set一样,Map会把Key类型一致,值类型一致的绑定到同一个Map中
@Module
public class MyModule1 {
@Provides
@IntoMap
@StringKey("foo")
static Long provideFooValue(){
return 100L;
//绑定到Map<String,Long>中
}
@Provides
@IntoMap
@StringKey("goo")
static Long provideGooValue(){
return 100L;
//绑定到Map<String,Long>中
}
@Provides
@IntKey(2)
@IntoMap
static int provideIntValue(){
return 200;
//绑定到Map<Integer Integer>中
}
@Provides
@IntoMap
@LongKey(1L)
static Long provideLongValue(){
return 100L;
//绑定到Map<Long,Long> 中
}
@Provides
@IntoMap
@ClassKey(Test3.class)
static String provideTest3Value(){
return "Value for Test3";
//key为Test3.class,用的是Dagger2的标注,所以key为Class<?>,值为String的Map<Class<?>,Sting>
}
}
在MyModule1 中,我们看到各种类型的@MapKey注解的给中MapKey。随便看个 @ClassKey的源码
@Beta
@Documented
@Target(METHOD)
@MapKey
public @interface ClassKey {
Class<?> value();
}
在MyModule2 中我们也自定义几个@MapKey的注解
@Module
public class MyModule2 {
@Provides
@IntoMap
@MyEnumKey(MyEnum.ABC)
public String provideABCValue() {
return "Value for ABC";
//绑定到 Map<MyModule2.MyEnum, String> 中去
}
@Provides
@IntoMap
@MyNumberClassKey(BigDecimal.class)
public String provideNumberClassValue() {
return "BigDecimal Value";
//绑定到Map< Class<? extends Number>,String>中
}
//自定义枚举
public static enum MyEnum {
ABC, DEF;
}
//自定义注解枚举类型的@MapKey
@MapKey
@interface MyEnumKey {
MyEnum value();
}
//自定义注解 @MapKey
@MapKey
@interface MyNumberClassKey {
Class<? extends Number> value();
}
}
然后我们看MainActivityComponent 的代码,同样,这里也有个抽象方法 Map<String, Long> getMap(); 把 Map<String, Long>的提供出去。也就是说 Map和Set一样。也有两种注入方式。这里我们只看一种。另一种和Set一样。
@OnlyInstance
@Component(dependencies = ApplicationComponent.class,modules = {ModuleA.class, ModuleB.class,MyModule1.class, MyModule2.class,CModule.class})
public interface MainActivityComponent {
void inject(MainActivity activity);
Set<String> getStrings();
Map<String, Long> getMap();
}
看注入的地方代码
public class MainActivity extends AppCompatActivity {
@Inject
Test3 test3;
@Inject
Test3 test2;
@Inject
Test2 test21;//注入这个需要提供Set<String>为参数
@Inject
Set<String> mStringSet;//注入的为Set<String>
@Inject
Map<Integer, Integer> mIntegerIntegerMap;//Key Integer,值为Integer
@Inject
Map<String, Long> mapTest;//Key为String,值为Long的就会注入到这个里面
@Inject
Map<Long, Long> mapLongkey;//key 为Long,值为Long的就会注入到这个里面
@Inject
Map<MyModule2.MyEnum, String> myEnumStringMap;
@Inject
Map<Class<? extends Number>, String> classStringMap;//自定义Key
@Inject
Map<Class<?>, String> test3StringMap;//key为Test3.class,用的是Dagger2的标注,所以key为Class<?>
@Inject
Set<Integer> integerSet;//注入的为 Set<Integer>
@Inject
@Named("boy")
Test5 boy;
@Inject
@Named("girl")
Test5 girl;
@Inject
@ForBoy
Test5 man;
@Inject
@ForGirl
Test5 woman;
@Inject
@ForGirl
Lazy<Test5> beautifulGirl;//漂亮的女孩都比较懒
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/* MainActivityComponent mainActivityComponent = DaggerMainActivityComponent
.builder()
.applicationComponent(((DemoApplication) getApplication()).component())
.build();
mStringSet = mainActivityComponent
.getStrings();*/
DaggerMainActivityComponent.builder()
.applicationComponent(((DemoApplication) getApplication()).component())
.build()
.inject(this);
Toast.makeText(this, test2.sayName(), Toast.LENGTH_SHORT).show();
Toast.makeText(this, beautifulGirl.get().signature(), Toast.LENGTH_SHORT).show();
//注入完成后只是提供一个可以生成Test5的对象,通过get(),才能获得我们需要的真正实例
}
}