IOC及依赖注入

IOC: Inversion Of Control

DI: Dependency Inject

Mode of Injection:

  1. Constructor Injection: Injecting the method parameters.
  2. Field Injection: Injecting the member variable (must not be private).
  3. Method Injection: Injecting the method parameter.

A dependency consumer asks for the dependency(Object) from a dependency provider through a connector.

  1. Dependency provider: Classes annotated with @Module are responsible for providing objects which can be injected. Such classes define methods annotated with @Provides. The returned objects from these methods are available for dependency injection.
  2. Dependency consumer: The @Inject annotation is used to define a dependency.
  3. Connecting consumer and producer: A @Component annotated interface defines the connection between the provider of objects (modules) and the objects which express a dependency. The class for this connection is generated by the Dagger.

上面的意思就是,要使用依赖注入,需要有三个元素组成。

  1. 依赖生产者,也就是我们用@Module标注的Module类
  2. 依赖关系消费者,使用@Inject用于定义依赖关系
  3. 连接消费者和生产者,也就是我们的@Component,在我们使用Dagger时,我们只需要定义接口,具体的类实现Dagger会帮我们实现

依赖

implementation 'com.google.dagger:dagger-android:2.46'
implementation 'com.google.dagger:dagger-android-support:2.46' // if you use the support libraries
annotationProcessor 'com.google.dagger:dagger-android-processor:2.46'
annotationProcessor 'com.google.dagger:dagger-compiler:2.46'

简单使用

构造方法注入

构建一个User实体类,在构造方法上使用@Inject注解

public class User {
/**
* 1.使用@Inject注解在构造方法上,就是告知Dagger可以通过构造方法来创建并获取到User的实例
*/
@Inject
public User() {

}
}

构造Component,定义inject方法,参数选择需要注入的Activity

@Component
public interface ApplicationComponent {
void inject(MainActivity mainActivity);
}

使用: 在Activity中需要执行注入动作

public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Inject
User user;
@Inject
User user2;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

//4.执行注入动作
DaggerApplicationComponent.builder().build().inject(this);
// DaggerApplicationComponent.create().inject(this);

Log.e(TAG, "onCreate: user --> " + user );
Log.e(TAG, "onCreate: user2 --> " + user2 );
}
}
使用Modules提供对象实例
  1. 创建Module,命名规则一般为 XXXModule
@Module
public class NetWorkModule {
/**
* 第二种方式,告知Dagger,可以通过该方法来获取要注入对象的实例
* @return
*/
@Provides
public Retrofit provideRetrofit() {
return new Retrofit.Builder()
.baseUrl("http://www.baidu.com")
.build();
}

@Provides
public ApiService provideApiService(@NonNull Retrofit retrofit) {
return retrofit.create(ApiService.class);
}
}
  1. 在Component中添加module
@Component(modules = NetWorkModule.class)
public interface ApplicationComponent {
void inject(MainActivity mainActivity);
}
  1. 使用方法和用构造方法注入一样

Dagger作用域限定

  • 使用作用域限定,可以将某个对象的生命周期限定为其组件的生命周期。这样也就意味着,在作用范围内,使用到的是同一实例
  • @Singleton是Dagger提供的一种默认的作用域注解,其意义表示一个单例对象。也就是实例的生命周期和程序运行的生命周期保持一致。
  • 使用@Scope实现自定义作用域注解
  • 作用域注解使用在@Inject、@Provides、@Binds、@Module、@Component注解上,表示其产生作用的范围。

第一点的意思,举个例子,如果我们在上面的Module中,将Retrofit 和 ApiService 都标注为@Singleton,我们也需要在其装载的组件,也就是ApplicationComponent中限定生命周期。

@Module
public class NetWorkModule {
/**
* 第二种方式,告知Dagger,可以通过该方法来获取要注入对象的实例
* @return
*/
@Provides
@Singleton //限定为单例
public Retrofit provideRetrofit() {
return new Retrofit.Builder()
.baseUrl("http://www.baidu.com")
.build();
}

@Provides
@Singleton //限定为单例
public ApiService provideApiService(@NonNull Retrofit retrofit) {
return retrofit.create(ApiService.class);
}
}
@Component(modules = NetWorkModule.class)
@Singleton //注意: 这里也要添加
public interface ApplicationComponent {
void inject(MainActivity mainActivity);
}

我们可以看一下Singleton的完整代码

@Scope
@Documented
@Retention(RUNTIME)
public @interface Singleton {}

可以看到,当然,这里也不一定要使用@Singleton,可以自定义任何的注解。

在上面的例子中,我们的RetrofitApiService都指定了相同的作用域,在其装载的组件ApplicationComponent,也指定了相同的作用域,也就是在ApplicationComponent组件的作用范围内,获取到的Retrofit都是统一对象

作用域和单例是两个不同的概念

@Singleton是Dagger提供的一种作用域实现

作用域就是用来管理Component来获取对象实例的生命周期的。

使用作用域遵循的一些规则

  • 在没有必要的情况下,尽量使用默认的作用域,即不指定作用域。
  • 使用作用域注解的模块也只能在带有相同作用域注解的组件中使用。
  • 作用域的指定,必须是上层对下层兼并的关系,这里把上下级分为三层:@Inject/@Provides/@Binds为第二层,@Module为一层,@Component为第三层。如果在上层指定了作用域,那么下层的作用域要么不指定,一旦指定只能保持和上层一致。
  • 开发设计时,一定要有清晰的依赖图,不然很容易产生依赖死循环。

组件依赖

重新为组件设置Module实例

存在这样的场景,需要重新设置Module实例:

  • 模块类中定义了一些需要用到的变量,这些变量不能通过Dagger直接注入,需要通过构造方法获得。
  • 默认情况下组件创建Module的实例方法使用的是无参构造方法。
  • 在执行注入动作时,需要通过重新设定组件的Module实例。

Dagger组件依赖与子组件

组件依赖与子组件主要解决了不同作用域时组件之间的复用问题:

  • 在一个组件指定作用域后,就已经确定了该组件创建对象的生命周期。但是有些对象的实例可能生命周期更短,这个时候就需要定义新的组件。
  • 新组件需要使用原组件的部分资源。

两种实现方式: