Dagger2进阶必备技能
之前拙荆有一篇文章介绍Dagger2的初步知识, 本篇文章主要介绍Dagger2的进阶知识点.
主要包含的内有有
- @Binds与@Provides的使用
- Provider
与Lazy 的使用 - 依赖与包含
- Dagger.Android
@Binds与@Provides
相信大家经常会使用@Provides来在Module里面提供需要注入对象的构造, 但从来没有用过@Binds.
如果我们需要注入一个接口的实现,我们常常会这么做:
1 | @Provides |
其实这样的代码可以通过@Binds简化为
1 | @Binds |
同时你需要将你的Module改为abstract即可, 但是要注意这两个不能共存于一个Module,是不是很简单.
Provider与Lazy
大家想必会使用过Lazy,很多语言都有Lazy,如最近大红大紫的Kotlin就可以通过by lazy {}来实现对象的延迟加载.
没错,Lazy<T>也是如此,只有当你调用get()时,才会真正注入.
Provider<T>与之的区别在于,Lazy延迟加载之后每次的调用都是同一个对象,而Provider则要看注入对象的实现,如果是通过@Scope约束的对象,则是同一个,否则每次都会创建新的.
依赖于包含
字面意思很好理解,翻译成Dagger的术语就是dependency与subcomponent.
下面分别举例子来说明其中的区别和使用方法.
Dependency
AnimalComponent
1 | @Component( |
AnimalModule
1 | @Module |
FoodComponent
1 | @Component(modules = FoodModule.class) |
这样我们可以通过传入FoodComponent来完成注入, 如下:
1 | DaggerAnimalComponent.builder().foodComponent(foodComponent).build().getAnimal() |
Subcomponent
与依赖不同,Subcomponent拥有主Component所有注入对象,也就是说Subcomponent可以注入更多的对象, 通过生成代码也可以看出, 它的实现是主Component的内部类.
Cat
1 | @Subcomponent(modules = {CatModule.class}) |
CatModule
1 | @Module |
我们还必须在AnimalComponent显示提供CatComponent,因为如上所述,Cat是Animal的内部类了.
1 | @Component( |
这样我们就可以通过下面的办法来实现Cat的注入:
1 | DaggerAnimalComponent.build().createCatComponent().getCat(); |
Subcomponent with explicit builder
当我们AnimalComponent需要对Cat进行修改再输出的话(如指定猫的名字),可能就需要为CatComponent提供Builder
1 | @Subcomponent(modules = {CatModule.class}) |
然后我们需要在AnimalModule里面使用这个Builder了
1 | @Module(subcomponents = CatComponent.class)//注意这里需要加上这一条声明 |
Dagger.Android
平时我们注入的时候常常都是将Component存在Application里面,然后在Acitivity的onCreate或者Fragment的onAttach, 通过静态对象Applicate.component.inject(xxx)或者((XXApplication)getApplication()).getComponent().inject(xxx)来注入.
我们常常需要记住在固定的生命周期里面调用固定的语句,如果你的Activity或者Fragment在别的module里面使用公开的接口,对于Fragment你还可以对其对象进行注入(inject(fragmentInstance)),然而对Activity可能就没有很好的办法了…
Google的Dagger2提供了一套针对Android的东西,帮助你只需要调用AndroidInjection.inject(this)或者AndroidSupportInjection.inject(this)来注入,甚至还可以通过添加一些监听器,达到自动注入的效果哦.
下来看看如何实现吧
添加依赖
1 | //x>=10 |
引入AndroidInjectionModule.class到你的Component
提供继承AndroidInjector<T>的Subcomponent, 及其Builder
1 | @Subcomponent(modules = ...) |
通过Builder提供对应Activity的AndroidInjector.Factory
1 | @Module(subcomponents = YourActivitySubcomponent.class) |
Tips
类似于之前介绍Subcomponent.Builder, 如果你不需要定制该Builder, 如添加方法之类的, 那么这上面两步可以做简化.
1 | @Module |
参数module可以把想要注入的Fragment抽象到YourFragmentModule一并注入.
实现HasActivityInjector
1 | public class YourApplication extends Application implements HasActivityInjector { |
实际上所有的注入构造的工场方法AndroidInjector.Factory都被存入了一个Map保存在DispatchingAndroidInjector,我们可以查看其生成的代码,其中核心逻辑在maybeInject(T instance)里
1 | public boolean maybeInject(T instance) { |
这就是其之所以能通过AndroidInjection.inject(this)实现注入的核心原理所在,Fragment同理.
当然你需要通过持有AndroidInjector Module的Component将这个DispatchingAndroidInjector注入了才行,一般可以在Application里面做.
实现自动注入.
由于使用Dagger.android扩展使注入入口得到统一,那么就可以通过添加监听的方式在activity与fragment创建的时候实现自动注入.
当然相信之后此部分代码可能会被融入进Dagger2.
1 | Application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() { |
总结
Dagger2.Android自2.10版本后推出,只有不到三个月,可见Dagger2还在不断自我强大的过程中,它的出现使得Android开发在很多层面变的简单,如果有希望进一步学习的朋友,可以参考官方文档和一些Google的Sample,会在最后的Reference给出连接.