Dagger
依赖注入(Dependency Injection),简称DI,又叫控制反转(Inversion of Control),简称IOC
当一个类的实例需要另一个类的实例,在传统的设计中,通常由调用者来创建被调用者的实例,然而依赖注入的方式,创建被调用者不再由调用者创建实例,创建被调用者的实例的工作由IOC容器来完成,然后注入到调用者。因此也被称为依赖注入
- API
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
31public @interface Component {
Class<?>[] modules() default {};
Class<?>[] dependencies() default {};
@Target(TYPE)
@Documented
@interface Builder {}
}
public @interface Subcomponent {
Class<?>[] modules() default {};
@Target(TYPE)
@Documented
@interface Builder {}
}
public @interface Module {
Class<?>[] includes() default {};
@Beta
Class<?>[] subcomponents() default {};
}
public @interface Provides {
}
public @interface MapKey {
boolean unwrapValue() default true;
}
public interface Lazy<T> {
T get();
}
@Inject声明依赖注入构造方法,自动请求参数并调用构造方法
1
2
3
4
5
6
7
8
9
10class Thermosiphon implements Pump {
private final Heater heater;
@Inject
Thermosiphon(Heater heater) {
this.heater = heater;
}
...
}@Inject fields 实例化成员变量
如果你的类有@Inject成员变量,但是没有@Inject构造方法,Dagger会注入这些变量,但是不会创建新的对象。所有添加@Inject无参的构造函数让Dagger也可以创建对象,也可以@Inject method(),当然Field,Constructor是首选。1
2
3
4
5class CoffeeMaker {
@Inject Heater heater;
@Inject Pump pump;
...
}@Inject不足
1
2
3
4类中只能包含一个@Inject constructor
接口,抽象类是没有构造方法的
第三方库提供的类,它们的构造方法不能被注解
有些类需要灵活选择初始化的配置,而不是使用一个单一的构造方法@Provides 可以满足上面的依赖性,但是必须属于一个Module,有一个惯例方法前缀加provide,类后缀加Module
1
2
3
4
5
6
7
8
9
10@Module
class DripCoffeeModule {
@Provides static Heater provideHeater() {
return new ElectricHeater();
}
@Provides static Pump providePump(Thermosiphon pump) {
return pump;
}
}@Component 在接口中,传入Module,完成接口和类的注入,将CoffeeShop 通过DripCoffeeModule注入到MainActivity中
@Component中使用modules,表明该Component在哪些注入的Module中查找依赖
@Component中使用dependencie,表明该Component在哪些注入的Component中查找依赖
添加注入方法,一般使用inject
可以声明方法,提供注入的实例1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18@Component(modules = DripCoffeeModule.class)
interface CoffeeShop {
CoffeeMaker maker();
}
CoffeeShop coffeeShop = DaggerCoffeeShop.builder()
.dripCoffeeModule(new DripCoffeeModule())
.build();
//如果@Component不是在类的上方,生成组件时需要添加下划线
class Foo {
static class Bar {
@Component
interface BazComponent {}
}
}
DaggerFoo_Bar_BazComponent如果所有的依赖关系都可以在不需要实例对象的情况下创建,那么可以使用builder(),也可以使用crete()创建实例,对于所有的@Provides方法都是静态的Module,可以不需要考虑builder
1
CoffeeShop coffeeShop = DaggerCoffeeShop.create();
针对在MainActivity中的依赖注入
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
62public class Car {
@Inject
public Car() {
}
public String show() {
return String.valueOf(1);
}
}
@Component
public interface MainActivityComponent {
void inject(MainActivity activity);
}
public class MainActivity extends AppCompatActivity {
@Inject
Car car;
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 先编译一次crtl+F9
DaggerMainActivityComponent.create().inject(this);
String show = car.show();
Toast.makeText(MainActivity.this, show, Toast.LENGTH_SHORT).show();
}
}
//Water 抽象类,@Inject无法提供实例
@Inject
public Car(Water water) {
}
//清除子类@Inject
//@Inject
public HotWater(){
}
// @Inject
public CoolWater(){
}
/**
*@Module标记在类上面
*@Provodes标记在方法上
*表示可以通过这个方法获取依赖
*/
@Module
public class WaterModule {
@Provides
Water provideWater(){
return new HotWater();
}
}
/**
* 在Component中指定Module
*/
@Component(modules = WaterModule.class)
public interface MainActivityComponent {
void inject(MainActivity mainActivity);
}
- @Module需要和@Provide是需要一起使用的时候才具有作用的,并且@Component也需要指定了Module
@Module是告诉Component,可以从这里获取依赖对象。Component就会去找被@Provide标注的方法,相当于构造器的@Inject可以提供依赖,@Component可以指定多个@Module的 Component可以包含多个Module或者Component,这样Component获取依赖时候会自动从多个Module中查找获取,但是,Module间不能有重复方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18在Component中的modules属性中注入多个Module
@Component(modules={ModuleA.class,ModuleB.class,...})
public interface FruitComponent{
...
}
在Component中的dependencies属性中注入多个依赖的Component
@Component(dependencies={ComponentA.class,ComponentB.class,...})
public interface FruitComponent{
...
}
在Module中注入多个Module
@Module(includes={ModuleA.class,ModuleB.class,...})
public class FruitModule{
...
}注入的Module,不管是属于Component本身还是注入的Module的依赖,如果其构造函数为有参构造函数,必须进行初始化
1
2
3DaggerFruitComponent.builder()
.orangeModule(new OrangeModule(new OrangeBean("贡菊", 6.88, "江西南昌")))
.build();依赖规则
步骤1:查找Module中是否存在创建该类的方法。步骤2:若存在创建类方法,查看该方法是否存在参数
步骤2.1:若存在参数,则按从步骤1开始依次初始化每个参数
步骤2.2:若不存在参数,则直接初始化该类实例,一次依赖注入结束步骤3:若不存在创建类方法,则查找Inject注解的构造函数,看构造函数是否存在参数
步骤3.1:若存在参数,则从步骤1开始依次初始化每个参数
步骤3.2:若不存在参数,则直接初始化该类实例,一次依赖注入结束在Component中,可以声明方法,比如makeApple(),直接提供注入对象实例。DaggerFruitComponent针对每一个@Provides方法创建Provider\<T>实例。在调用makeApple()方法时,实际上是调用的相应Provider的get()方法,获取相应的实例
1
2
3public AppleBean makeApple() {
return provideAppleProvider.get();
}依赖对象的注入源应该是有两个,一是Module中的@Provides方法,二是使用@Inject注解的构造函数
单例@Singleton,可以做文档注释,提醒是线程安全
1
2
3@Provides @Singleton static Heater provideHeater() {
return new ElectricHeater();
}@Qualifier是限定符,而@Named则是基于String的限定符,容易写错,推荐@Qualifier 自定义注解
1
2
3
4
5
6
7
8
9
10
11
12@Provides
@CoolQualifier
// @Named("Cool")
Water provideCoolWater() {
return new CoolWater();
}
// 另外的一种方式,这里Water是抽象类,可以考虑其他对象Light灯光
// @Provides
// Water providePot(@CoolQualifier Water w) {
// return new Water(w);
// }@Component与@SubComponent
Car
1
2
3
4
5@Inject
public Car(Water water) {
this.water = water;
oil = new Oil();
}WaterComponent
1
2
3
4
5
6
7
8
9
10
11
12/**
* @Module标记在类上面
* @Provodes标记在方法上 表示可以通过这个方法获取依赖
*/
@Component(modules = WaterModule.class)
public interface WaterComponent {
@HotQualifier
Water getHotWater();
@CoolQualifier
Water getCoolWater();
}CarModule
1
2
3
4
5
6
7@Module
public class CarModule {
@Provides
Car provideCar(@CoolQualifier Water water){
return new Car(water);
}
}CarComponent
1
2
3
4
5
6
7
8/**
* @Module标记在类上面
* @Provodes标记在方法上 表示可以通过这个方法获取依赖
*/
@Component(modules = CarModule.class, dependencies = WaterComponent.class)
public interface CarComponent {
Car getCar();
}MainActivityComponent
1
2
3
4@Component(dependencies = CarComponent.class)
public interface MainActivityComponent {
void inject(MainActivity mainActivity);
}MainActivity
1
2
3
4
5
6
7DaggerMainActivityComponent.builder()
.carComponent(DaggerCarComponent.builder()
.waterComponent(DaggerWaterComponent.create())
.build())
.build()
.inject(this);
Log.e(TAG, car.show());- CarComponent依赖WaterComponent,将WaterComponent的引用传递给CarComponent,这样CarComponent就可以使用WaterComponent中的方法。
在DaggerCarComponent中的getCar()方法,waterComponent.getCoolWater()获取Water 通过@SubComponent实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14@Component(modules = WaterModule.class)
public interface WaterComponent {
CarComponent plus(CarModule carModule);
}
@Subcomponent(modules = CarModule.class)
public interface CarComponent{
MainActivityComponent plus();
}
@Subcomponent
public interface MainActivityComponent {
void inject(MainActivity mainActivity);
}Component和SubComponent区别
1
2
3
4Component dependencies 能单独使用,而Subcomponent必须由Component调用方法获取。
Component dependencies 可以很清楚的得知他依赖哪个Component, 而Subcomponent不确定
使用上的区别,Subcomponent就像这样DaggerAppComponent.plus(new SharePreferenceModule());
使用Dependence可能是这样DaggerAppComponent.sharePreferenceComponent(SharePreferenceComponent.create())
@Scope和@Singleton
@Scope管理依赖的生命周期,@Scope对某类注解后,其作用的核心应该是注入器的控制,注入实例时,控制注入器调用缓存的实例还是重新实例,自定义注解,而@Singleton是@Scope默认实现
如果有类注入实例的类被@Scope注解,那么其Component必须被相同的Scope注解1
2
3
4@Scope
@Documented
@Retention(RUNTIME)
public @interface Singleton {}依赖实例的注入来源是@Provides方法时,@Provides方法必须被@Scope注解;如果依赖实例的注入来源是@Inject注解的构造函数时,实例类必须被@Scope注解。这样@Scope注解才会有效。也就是说,@Scope实际上是对注入器的控制
Scope控制的实例的注入器是当前Component之内的实例注入器,而不会影响其他的Component中的实例注入器
更好的管理Component之间的组织方式,用自定义的Scope注解标注这些Component,检查有依赖关系或包含关系的Component,若发现Component没有用自定义Scope注解标注,则会报错
- 编译器会检查 Component管理的Modules,标注Component的自定义Scope注解与Modules中的标注创建类实例方法的注解不一样会报错
单例实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20@Inject
Car car1;
//可以注入多个Car,但是重新创建了一个依赖
@Inject
Car car2;
//使用单例,@Singleton
@Module
public class CarModule {
@Provides
@Singleton
Car provideCar(@CoolQualifier Water water){
return new Car(water);
}
}
@Singleton
@Component(modules = CarModule.class, dependencies = WaterComponent.class)
public interface CarComponent {
Car getCar();
}编译报错
1
2Error:(16, 1) 错误: com.willkernel.www.daggerdemo.component.MainActivityComponent (unscoped) cannot depend on scoped components:
@Singleton com.willkernel.www.daggerdemo.component.CarComponent- 在Component中指定Module
MainActivityComponent依赖CarComponent
而dagger2规定使用单例的Component,子Component也必须标注@Scope
但是不能标注@Singleton,不允许,单例依赖单例不符合设计原则
需要自定义一个@Scope,例如ActivityScope
@Singleton 需要在@Provide和@Component,还有MainActivityComponent中使用@Scope
才能够顺利编译,保持局部单例 - 可以注入多个Car,但是重新创建了一个依赖,使用单例后两个地址一样,
但是在其他Activity中,地址又不一样,属于局部单例,在其他Activity重新
创建了注入器Component,所以Car对象的地址改变了 Dagger正确使用单例
依赖在Component中是单例的(供该依赖的provide方法和对应的Component类使用同一个Scope注解)
对应的Component在App中只初始化一次,每次注入依赖都使用这个Component对象(在Application中创建该Component)App
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class App extends Application {
private CarComponent carComponent;
@Override
public void onCreate() {
super.onCreate();
carComponent = DaggerCarComponent.builder()
.waterComponent(DaggerWaterComponent.create())
.build();
}
public CarComponent getCarComponent() {
return carComponent;
}
}SecondActivity
1
2
3
4
5
6
7
8@Inject
Car car3;
DaggerSecondActivityComponent.builder()
.carComponent(((App) getApplication()).getCarComponent())
.build()
.inject(this);
Log.e(TAG, "car3=" + car3.hashCode());也可以通过ApplciationScope使用单例
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@Scope
@Retention(RUNTIME)
public @interface ApplicationScope {
}
public class App extends Application{
@Inject
Car car;
@Override
public void onCreate() {
super.onCreate();
DaggerAppComponent.builder().carComponent(DaggerCarComponent.builder() .waterComponent(DaggerWaterComponent.create()).build())
.build()
.inject(this);
}
public Car getCar() {
return car;
}
在SecondeActivity中引用
car6=((App)getApplication()).getCar();
Log.e(TAG, "car6=" + car6.hashCode());MapKey
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@Component(modules = MapKeyModule.class)
public interface MapComponent {
Map<String, String> mapkey();
}
@Module
public class MapKeyModule {
@Provides
@IntoMap
@TestKey("foo")
String provideFooKey() {
return "foo value";
}
@Provides
@IntoMap
@TestKey("bar")
String provideBarKey() {
return "bar value";
}
}
@MapKey(unwrapValue = true)
public @interface TestKey {
String value();
}
Map<String, String> map = DaggerMapComponent.create().mapkey();
Log.e(TAG, "map " + map.toString());Lazy
通过Lazy提供的实例,在@Inject的时候并不初始化,而是使用的时候,主动调用其get方法来获取实例,并且会缓存该对象1
2
3
4
5@Inject
Lazy<Car> carLazy;
Car carL = carLazy.get();
Log.e(TAG, "carL " + carL.show());Provider
有时您需要注入多个实例列表,而不是注入单个值。可以注入一个Provider,而不只是T。
当Provider每次调用get()方法时,都会执行绑定逻辑并创建一个新的实例,地址不一样,但@Scope注解的类地址是一样的 1
2
3
4
5
6
7
8
9
10
11
12
13
14@CoffeeScope
public class CoffeeBean {
@Inject
public CoffeeBean() {
Log.d("test", "Coffee()");
}
}
@Inject
Provider<CoffeeBean> mCoffeeBeanProvider
CoffeeBean beanA = mCoffeeBeanProvider.get();
CoffeeBean beanB = mCoffeeBeanProvider.get();多个元素绑定并注入到Set
将单个元素注入到Set
1
2
3
4
5
6
7@Module
class MyModuleA {
@Provides @IntoSet
static String provideOneString(DepA depA, DepB depB) {
return "ABC";
}
}Set
注入到Set 1
2
3
4
5
6
7@Module
class MyModuleB {
@Provides @ElementsIntoSet
static Set<String> provideSomeStrings(DepA depA, DepB depB) {
return new HashSet<String>(Arrays.asList("DEF", "GHI"));
}
}在Component中,表明注入到Set的实例的提供Module,声明setApple()方法,用来提供集合Set
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17class Bar {
@Inject Bar(Set<String> strings) {
assert strings.contains("ABC");
assert strings.contains("DEF");
assert strings.contains("GHI");
}
}
或者
@Component(modules = {MyModuleA.class, MyModuleB.class})
interface MyComponent {
Set<String> strings();
}
@Test void testMyComponent() {
MyComponent myComponent = DaggerMyComponent.create();
assertThat(myComponent.strings()).containsExactly("ABC", "DEF", "GHI");
}
也可以通过Provider<Set
> or Lazy<Set >来依赖注入实例,但是不能通过Set<Provider >> 增加限定符@Qualifier
1
2
3
4
5
6
7
8
9
10
11
12
13
14@Module
class MyModuleC {
@Provides @IntoSet
@MyQualifier
static Foo provideOneFoo(DepA depA, DepB depB) {
return new Foo(depA, depB);
}
}
@Module
class MyModuleD {
@Provides
static FooSetUser provideFooSetUser(@MyQualifier Set<Foo> foos) { ... }
}多个元素绑定并注入到Map
在Module中的@Provides方法使用@IntoMap,同时指定该元素的Key(例如@StringKey(“foo”),@ClassKey(Thing.class),@IntKey(12),@LongKey(100L)),没有这个key时,返回null1
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@Module
class MyModule {
@Provides @IntoMap
@StringKey("foo")
static Long provideFooValue() {
return 100L;
}
@Provides @IntoMap
@ClassKey(Thing.class)
static String provideThingValue() {
return "value for Thing";
}
}
@Component(modules = MyModule.class)
interface MyComponent {
Map<String, Long> longsByString();
Map<Class<?>, String> stringsByClass();
}
@Test void testMyComponent() {
MyComponent myComponent = DaggerMyComponent.create();
assertThat(myComponent.longsByString().get("foo")).isEqualTo(100L);
assertThat(myComponent.stringsByClass().get(Thing.class))
.isEqualTo("value for Thing");
}- 如果key是枚举或其他特定的类,使用@MapKey注解,自定义Key
自定义枚举类型,数据包装类key
如果不满足指定的返回类型,那么编译时会报错:
基本数据类型
String
Class(参数化类,? extends Number)
枚举类型
注解类型
以上数据类型的数组1
2
3
4
5
6
7
8
9
10
11
12
13enum MyEnum {
ABC, DEF;
}
@MapKey
@interface MyEnumKey {
MyEnum value();
}
@MapKey
@interface MyNumberClassKey {
Class<? extends Number> value();
}在Module中的@Prvoides使用@IntoMap,并指明key
1
2
3
4
5
6
7
8
9
10
11
12
13
14@Module
class MyModule {
@Provides @IntoMap
@MyEnumKey(MyEnum.ABC)
static String provideABCValue() {
return "value for ABC";
}
@Provides @IntoMap
@MyNumberClassKey(BigDecimal.class)
static String provideBigDecimalValue() {
return "value for BigDecimal";
}
}注入器Component
1
2
3
4
5
6
7
8
9
10
11
12@Component(modules = MyModule.class)
interface MyComponent {
Map<MyEnum, String> myEnumStringMap();
Map<Class<? extends Number>, String> stringsByNumberClass();
}
@Test void testMyComponent() {
MyComponent myComponent = DaggerMyComponent.create();
assertThat(myComponent.myEnumStringMap().get(MyEnum.ABC)).isEqualTo("value for ABC");
assertThat(myComponent.stringsByNumberClass.get(BigDecimal.class))
.isEqualTo("value for BigDecimal");
}组合的MapKey,设置unwrapValue的值为false,这样key值也可以是数组成员,key不唯一指定,可以有多个不同类型的key
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20@MapKey(unwrapValue = false)
@interface MyKey {
String name();
Class<?> implementingClass();
int[] thresholds();
}
@Module
class MyModule {
@Provides @IntoMap
@MyKey(name = "abc", implementingClass = Abc.class, thresholds = {1, 5, 10})
static String provideAbc1510Value() {
return "foo";
}
}
@Component(modules = MyModule.class)
interface MyComponent {
Map<MyKey, String> myKeyStringMap();
}使用MapKey,需要生成Mykey的静态方法,就需要使用@AutoAnnotation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15apt 被annotationProcessor替代
apply plugin: 'com.neenbedankt.android-apt'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
annotationProcessor "com.google.auto.value:auto-value-annotations:1.5"
implementation "com.google.auto.value:auto-value:1.5"
@AutoAnnotation
static MyKey createMyKey(String name, Class<?> implementingClass, int[] thresholds) {
return new AutoAnnotation_MainActivity_createMyKey(name, implementingClass, thresholds);
}
MyKeyComponent myKeyComponent = DaggerMyKeyComponent.create();
Log.e(TAG, "myKeyComponent "+myKeyComponent.myKeyStringMap()
.get(createMyKey("abc", BigDecimal.class, new int[]{1, 2, 4})));Mapkey的key在编译期间未知,就不能创建Mapkey的绑定,不过可以先设置绑定Set,再转换为Map绑定
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@Module
class MyModule {
@Provides @IntoSet
static Map.Entry<Foo, Bar> entryOne(...) {
Foo key = ...;
Bar value = ...;
return new SimpleImmutableEntry(key, value);
}
@Provides @IntoSet
static Map.Entry<Foo, Bar> entryTwo(...) {
Foo key = ...;
Bar value = ...;
return new SimpleImmutableEntry(key, value);
}
}
@Module
class MyMapModule {
@Provides
static Map<Foo, Bar> fooBarMap(Set<Map.Entry<Foo, Bar>> entries) {
Map<Foo, Bar> fooBarMap = new LinkedHashMap<>(entries.size());
for (Map.Entry<Foo, Bar> entry : entries) {
fooBarMap.put(entry.getKey(), entry.getValue());
}
return fooBarMap;
}
}Dagger并不会自动注入Map\<Foo,Provider\<Bar>>,也就意味着不会提供一个含有Provider值得Map。如果想要获取一个含有Provider的Map,需要在Map.Entry对象中包含Provider值,那么所获取的Map也就含有Provider
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18@Module
class MyModule {
@Provides @IntoSet
static Map.Entry<Foo, Provider<Bar>> entry(
Provider<BarSubclass> barSubclassProvider) {
Foo key = ...;
return new SimpleImmutableEntry(key, barSubclassProvider);
}
}
@Module
class MyProviderMapModule {
@Provides
static Map<Foo, Provider<Bar>> fooBarProviderMap(
Set<Map.Entry<Foo, Provider<Bar>>> entries) {
return ...;
}
}
声明多重绑定@Multibinds-annotated,也可以使用@IntoSet,@IntoMap,@ElementsIntoSet,但是必须有一个
1
2
3
4
5
6
7@Module
abstract class MyModule {
@Multibinds abstract Set<Foo> aSet();
@Multibinds @MyQualifier abstract Set<Foo> aQualifiedSet();
@Multibinds abstract Map<String, Foo> aMap();
@Multibinds @MyQualifier abstract Map<String, Foo> aQualifiedMap();
}Set或Map多重绑定可以声明任意次数而不会发生错误。Dagger从不实现或调用任何@Multibinds方法
添加返回空集合的@ElementsIntoSet方法1
2
3
4
5
6
7@Module
class MyEmptySetModule {
@Provides @ElementsIntoSet
static Set<Foo> primeEmptyFooSet() {
return Collections.emptySet();
}
}添加子组件方式
@Component的dependencies属性依赖父组件
1
2
3
4@Component(modules = OrangeModule.class, dependencies = FruitComponent.class)
public interface OrangeComponent {
***
}@Module的Subcomponents添加子组件
1
2
3
4
5@Module(subcomponents = AppleSubcomponent.class)
public class FruitModule {
***
}
@SubComponent声明子组件,需要提供@Subcomponent.Builder接口的Builder,build()来构建子组件
1
2
3
4
5
6
7
8
9
10@Subcomponent(modules = RequestModule.class)
interface RequestComponent {
RequestHandler requestHandler();
@Subcomponent.Builder
interface Builder {
Builder requestModule(RequestModule module);
RequestComponent build();
}
}添加子组件到父组件,添加子组件类到父组件的@Module的subcomponents属性,然后父组件调用子组件的builder方法
1
2@Module(subcomponents = RequestComponent.class)
class ServerModule {}父组件的注入器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21@Singleton
@Component(modules = ServerModule.class)
interface ServerComponent {
RequestRouter requestRouter();
}
子组件实例注入
@Singleton
class RequestRouter {
@Inject RequestRouter(
Provider<RequestComponent.Builder> requestComponentProvider) {}
void dataReceived(Data data) {
RequestComponent requestComponent =
requestComponentProvider.get()
.data(data)
.build();
requestComponent.requestHandler()
.writeResponse(200, "hello, world");
}
}子组件和作用域,如果没有作用域的绑定,每次注入都会重新创建独立的对象,但是如果有作用域绑定的对象,在作用域生命周期中绑定的对象实例是同一个
子组件和父组件的作用域不能相同,比父组件的生命周期短,两个子组件有不同的作用域实例,即使他们的作用域注解相同
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16@Singleton @Component
interface RootComponent {
SessionComponent.Builder sessionComponent();
}
@SessionScope @Subcomponent
interface SessionComponent {
FooRequestComponent.Builder fooRequestComponent();
BarRequestComponent.Builder barRequestComponent();
}
@RequestScope @Subcomponent
interface FooRequestComponent {...}
@RequestScope @Subcomponent
interface BarRequestComponent {...}封装子组件
在不同Service,不同界面,共享某些绑定,但是这些绑定中也有不需要的绑定实例,这时就需要使用子组件,对绑定实例进行细分应用ApplicationComponent,注入数据库实例
1
2
3
4
5@Singleton
@Component(modules = DatabaseModule.class)
interface ApplicationComponent {
Database database();
}数据库模块,子组件为DatabaseComponent
1
2
3
4
5
6
7
8
9
10
11
12
13@Module(subcomponents = DatabaseComponent.class)
class DatabaseModule {
@Provides
@Singleton
Database provideDatabase(
@NumberOfCores int numberOfCores,
DatabaseComponent.Builder databaseComponentBuilder) {
return databaseComponentBuilder
.databaseImplModule(new DatabaseImplModule(numberOfCores / 2))
.build()
.database();
}
}数据库实现类模块
1
2
3
4
5
6@Module
class DatabaseImplModule {
DatabaseImplModule(int concurrencyLevel) {}
@Provides DatabaseConnectionPool provideDatabaseConnectionPool() {}
@Provides DatabaseSchema provideDatabaseSchema() {}
}子组件
1
2
3
4@Subcomponent(modules = DatabaseImplModule.class)
interface DatabaseComponent {
@PrivateToDatabase Database database();
}
抽象工厂方法定义子组件
扩展多重绑定
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@Subcomponent(modules = DatabaseImplModule.class)
interface DatabaseComponent {
@PrivateToDatabase Database database();
}
@Module
class ParentModule {
@Provides @IntoMap
@StringKey("one") static int one() {
return 1;
}
@Provides @IntoMap
@StringKey("two") static int two() {
return 2;
}
@Provides @IntoSet
static String a() {
return "a"
}
@Provides @IntoSet
static String b() {
return "b"
}
}
@Subcomponent(modules = ChildModule.class)
interface Child {
Map<String, Integer> map();
Set<String> set();
}
@Module
class ChildModule {
@Provides @IntoMap
@StringKey("three") static int three() {
return 3;
}
@Provides @IntoMap
@StringKey("four") static int four() {
return 4;
}
@Provides @IntoSet
static String c() {
return "c"
}
@Provides @IntoSet
static String d() {
return "d"
}
}
Parent parent = DaggerParent.create();
Child child = parent.child();
assertThat(parent.map().keySet()).containsExactly("one", "two");
assertThat(child.map().keySet()).containsExactly("one", "two", "three", "four");
assertThat(parent.set()).containsExactly("a", "b");
assertThat(child.set()).containsExactly("a", "b", "c", "d");模块Module作为工厂方法的参数会在编译时报错,重复模块Module在依赖注入获取对象时引用是运行时错误
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21@Component(modules = {RepeatedModule.class, ...})
interface ComponentOne {
ComponentTwo componentTwo(RepeatedModule repeatedModule); // COMPILE ERROR!
ComponentThree.Builder componentThreeBuilder();
}
@Subcomponent(modules = {RepeatedModule.class, ...})
interface ComponentTwo { ... }
@Subcomponent(modules = {RepeatedModule.class, ...})
interface ComponentThree {
@Subcomponent.Builder
interface Builder {
Builder repeatedModule(RepeatedModule repeatedModule);
ComponentThree build();
}
}
DaggerComponentOne.create().componentThreeBuilder()
.repeatedModule(new RepeatedModule()) // UnsupportedOperationException!
.build();
Dagger Android
引入Dagger
1
2
3
4
5
6
7// Dagger dependencies
annotationProcessor "com.google.dagger:dagger-compiler:$rootProject.daggerVersion"
provided 'org.glassfish:javax.annotation:10.0-b28'
compile "com.google.dagger:dagger:$rootProject.daggerVersion"
compile "com.google.dagger:dagger-android:$rootProject.daggerVersion"
compile "com.google.dagger:dagger-android-support:$rootProject.daggerVersion"
annotationProcessor "com.google.dagger:dagger-android-processor:$rootProject.daggerVersion"@Binds
注解委托绑定模块的抽象方法,例如绑定Random到SecureRandom模块1
@Binds abstract Random bindRandom(SecureRandom secureRandom);
- 是@Provides的替代方法,更高效
- @Binds method
必须是抽象方法
必须是一个可以转换为返回值类型的参数,参数是返回值类型的子类或实现类,将返回值类绑定到参数类,将参数暴露为返回值类型,不需要实例化参数对象
可以有限定符@Qualified和作用域@Scoped1
2
3
4@Documented
@Retention(RUNTIME)
@Target(METHOD)
public @interface Binds {}
@ContributesAndroidInjector
注解的方法生成的返回值对应的AndroidInjector。该注入器是 dagger.Subcomponent的实现,而且是dagger.Module 的子Component
用于注解返回具体的Android框架类型(例如:FooActivity、BarFragment、MyService等)的dagger.Module中的无参抽象方法BindsInstance 标识组件或子组件的Builder方法,绑定对象到组件中的类
1
2
3
4
5@Documented
@Retention(RUNTIME)
@Target(METHOD)
@Beta
public @interface BindsInstance {}注入实例
由于DispatchingAndroidInjector在运行时由类查找相应的AndroidInjector.Factory,那么,在基类中,实现HasActivityInjector/HasFragmentInjector接口,在相应的声明周期(onCreate()或者onAttach())内调用AndroidInjection.inject()方法,注入相应的实例。所有每个子类都需要做的是绑定相应的@Subcomponent,从而没有必要在每个实例类中调用AndroidInjection.inject()方法。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16@Beta
public abstract class DaggerActivity extends Activity implements HasFragmentInjector {
@Inject DispatchingAndroidInjector<Fragment> fragmentInjector;
@Override
protected void onCreate(Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
}
@Override
public AndroidInjector<Fragment> fragmentInjector() {
return fragmentInjector;
}
}- 在dagger.android库中,有一些基本类型,对于Appliaction是DaggerApplication,只需重写applicationInjectoer()方法来返回AndroidInjector\<XxApplication>
Dagger提供的基本类型:
DaggerActivity
DaggerFragment
DaggerService
DaggerIntentService
DaggerBroadcastReceiver
DaggerContentProvider
- 在dagger.android库中,有一些基本类型,对于Appliaction是DaggerApplication,只需重写applicationInjectoer()方法来返回AndroidInjector\<XxApplication>