Dagger2 入门有这篇就够了(晋级篇)

Dagger2 入门晋级篇,直奔主题吧!
一 :组件之间的依赖
  1. 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,子组件(公共组件)
  1. 如果有一个组件,是每次创建实例提供给别人,而恰好其他组件(有多个)里面有需要它,如果只有一个,我们就用依赖搞定啦。多个它就可以定义成子组件,谁需要在谁的组件里面加一下,具体看例子.(提示: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注解;
  1. 如何实现单例,依然是看代码
  • 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方法里使用注解实现单例
3171886-4e9075dd2de19ba2.jpg
image

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 {
}
  1. 我们自定义的注解@OnlyInstance 和Dagger2提供的注解@Singleton,效果相同。他们都能实现单例,因为中间都有@Scope这个注解。
  2. @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();
    }
}

然后我们看下效果图


3171886-673e393ed0d9a8c8.jpg
image
  • 子组件提供的类的实例无法通过注解的方式直接实现单例,但是我们可以通过只获取一个子组件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;
}
}
3171886-1412eda5b0d7ff70.jpg
dagger2-4
单例的总结:我们自定义单例注解的时候,最好每个自定义的名称都有意义,比如在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;
    }
}
3171886-43edb666a72c9cf4.jpg
dagger2_9
  • 等等,我们不是说自定义注解的吗?是的,@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;
    }
}
3171886-cf2e286d66ae8d4c.jpg
image
  • 另外,如果我们把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();
}

现在就该到注入环节了。注入方式有两种哦

  1. 第一种注入方式,我们定义了相应类型的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);
    }
}
3171886-7986ee4663de558b.jpg
image

如果我们在Component中移除ModuleB那么ModuleB中提供的相应元素就不会注入到相应Set中了,另外Dagger2会把数据类型相同的都注入到同一个Set中,提供类型为 Set<Integer>注入到integerSet里,提供类型为Set<String>mStringSet中。

  1. 第二种方式:还记得我们刚在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();
       
    }
}

看效果图
3171886-0d8d54e05baeb9b0.jpg
image
多绑定到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(),才能获得我们需要的真正实例
    }
}
3171886-655caf4975614ff1.jpg
image
Map和Set的原理是一样的,只是Map的key可以通过自定义的方式来定义。对着撸一把。那么Demo地址:DaggerTest
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值