前面我写了Dagger2中2种注入的基本用法,这篇文章来讲下Dagger2比较高级一点的用法。本文也是个人学习思考所得,如有错误之处,还请大家多多评论交流。
@Component间的依赖
在Dagger2中2种注入的基本用法中,我们按照大多数情况,按页面划分Component类,既一个页面对应一个Component类,这样便于管理。事实上除了在Activity的生存周期内的属性需要注入,很多情况下在Application生存周期内也有属性可以通过Dagger2来注入,这种属性一般是供整个应用来使用的。
因此如大部分教程一样,我们会定义一个全局的Component类来对应于应用的Application类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| @Module public class MainApplicationModule { private MainApplication application; MainApplicationModule(MainApplication application) { this.application = application; } @Provides public Context providerApplicationContext() { return application; } }
@Component(module = MainApplicationModule.class) public interface MainApplicationComponent{ void inject(MainApplication mainApplication); }
public class MainApplication extends Application { private MainApplicationComponent component; @Override public void onCreate() { component = DaggerMainApplicationComponent.builder() .MainApplicationModule(new MainApplicationModule(this)) .build(); component().inject(this); } }
|
在MainModule中我们提供了ApplicationContext类型的注入。前面说到Application类的提供的注入是供整个应用使用的,那么如果MainActivity需要使用到MainModule中提供的ApplicationContext类型怎么办?这里就要用到Component间的依赖了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
|
@Component(dependencies = MainApplicationComponent.class, module = MainActivityModule.class) public interface MainActivityComponent{ void inject(MainActivity mainActivity); }
@Component(module = MainApplicationModule.class) public interface MainApplicationComponent{ void inject(MainApplication mainApplication); Context getApplicationContext(); }
public class MainApplication extends Application { private MainApplicationComponent component; public MainApplicationComponent getComponent() { return component; } }
public class MainActivity extends AppCompatActivity { MainActivityComponent mainComponent; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mainComponent = DaggerMainActivityComponent.builder() .applicationComponent(((MainApplication) getApplication()).getComponent()) .build(); mainComponent.inject(this); } }
|
总结一下:需要依赖其他Component(一般称为子Component)需要在@Comopnent注解中定义dependencies参数,而被依赖的Component(一般称为父Component),需要将可为子Component提供的注入类型,定义成方法,以返回值来提供。
@SubComponent
@SubComponent从名字上就可以看出来其意思:子Component。上节讲的Component间的依赖也有子Component,那这2种子Component有什么区别呢。
其中最大的区别,就是前一种情况,父Component需要显式的增加相关返回值的方法;而@SubComponent定义了相关的子Component后,仅需在父Component中定义返回该子Component的方法。
另外从项目开发进程的角度,前一种情况,一般是定义了父Component后,比如MainApplicationComponent,一般这种Component可能会被其他Compoennt依赖,为了方便以后扩展,我们无论是否有子Compoenent依赖,都先将其可以提供的注入依赖定义为方法。而当某个子Component需要扩展时,则在@Comopnent注解中定义dependencies参数即可。
而后一种情况,MainActivityComponent所注入的Activity,可能我们没办法预见其会需要一个子Component(这种子Component一般是跟其有关系的Activity或者Fragment),因此,如果MainActivity页面后面需要托管某个Fragment,比如MainFragment,则先用@SubComponent注释MainFragmentComponent,然后再修改MainActivityComponent,加上返回MainFragmentComponent的方法。
即,前一种情况,父Component对子Component无感知,而后一种情况则恰恰相反,子Component不清楚其父Component。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| @Component(dependencies = MainApplicationComponent.class, module = MainActivityModule.class) public interface MainActivityComponent{ void inject(MainActivity mainActivity); MainFragmentComponent getMainFragmentComponent(); }
@SubComponent public interface MainFragmentComponent { void inject(MainFragment mainFragment); }
public class MainActivity extends AppCompatActivity { MainActivityComponent mainComponent; public MainActivityComponent getMainActivityComponent() { return mainComponent; } }
public class MainFragment extends Fragment { MainFragmentComponent mainFragmentComponent; public void onActivityCreated(Bundle savedInstanceState) { mainFragmentComponent = ((MainActiivty) getActivity).getMainActivityComponent() .getMainFragmentComponent(); mainFragmentComponent.inject(this); } }
|
@Scope
@Scope用来限定@Module或@Inject提供的注入元素的作用域。在Java开发中,最常用的设计模式就是单例模式了,单例模式即类在整个应用生命周期或者某一段生命周期中只有一个实例。而Java提供了@Singleton用于注解仅单个实例的类。Dagger2使用@Scope来注解自定义的作用域类,自定义的@Scope类可以作用于@Component类或者@Provides方法,表示整个@Component提供的注入元素均为单例,或者某个@Provides方法提供的注入元素为单例。
此处的单例,是跟随@Component类的实例生存周期一致的,而@Component类如果是在Application中初始化,则很明示整个APP应用生命周期内,该@Component提供的注入元素为单例,如果是在Activity内onCreate方法中初始化,则只要onCreate方法不再次被调用(一般就是Activity的生命周期),则@Component提供的注入元素为单例。
所以无论是@Singleton还是自定义的@Scope,其实是跟随@Component的被初始化情况来决定单例的作用域的,而他们更大的作用,其实是为了增强代码可读性。比如@ApplicationScope、@ActivityScope。其中@Module提供注入方法注解的@Scope必须与@Module类注解的@Scope一致,比如均为@Singleton或者@PerActivity。而@Component之间有依赖关系的,如果都有@Scope修饰,则不能为相同@Scope注解,否则编译会报错。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
@Scope public @interface PerActivity { }
@Module public class MainApplicationModule { private MainApplication application; MainApplicationModule(MainApplication application) { this.application = application; } @Singleton @Provides public Context providerApplicationContext() { return application; } }
@Singleton @Component(module = MainApplicationModule.class) public interface MainApplicationComponent{ void inject(MainApplication mainApplication); Context getApplicationContext(); }
@PerActivity @Component(dependencies = MainApplicationComponent.class, module = MainActivityModule.class) public interface MainActivityComponent{ void inject(MainActivity mainActivity); MainFragmentComponent getMainFragmentComponent(); }
@Scope public @interface PerFragment { }
@PerFragment @SubComponent public interface MainFragmentComponent { void inject(MainFragment mainFragment); }
|
@IntoSet/@ElementsIntoSet
@IntoMap和@ElementsIntoSet其实很好理解,可以用来注入集合。@IntoMap注入Map,@ElementsIntoSet注入Set。看代码就明白了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| @Module public class MainActivityModule{ @IntoMap @StringKey("name") @Provides String providerName() { return "name"; } @IntoMap @StringKey("pwd") @Provides String providerPwd() { return "pwd"; } @ElementsIntoSet String providerName() { return "lilei"; } @ElementsIntoSet String providerMoreName() { return "zhangshang"; } }
public class MainActivity extends AppCompatActivity { @Inject HashMap<String> nameMap; @Inject HashSet<String> nameSet; }
|
Dagger2的知识点差不多就这些了。@IntoMap和@ElementsIntoSet其实很简单,不过可能用到的没那么多,因此放到这一章文章中。
以上内容均为个人学习理解,如果有错误之处,可以评论告诉我。共同学习,共同进步。