Dagger2四种使用方式
1. 什么是Dagger2
Dagger2是用来解决对象之间的高度耦合的框架。介绍Dagger2四种方式实现。
具体的四种使用场景
0. 配置
app模块下的build.gradle
dependencies {
//...其他依赖信息
implementation 'com.google.dagger:dagger:2.44'
annotationProcessor 'com.google.dagger:dagger-compiler:2.44'
}
1. 第一种实现方式
自己实现的代码可以在代码的构造函数上通过@Inject
修饰,实现代码注入,如下:
1. 实现细节
public class SingleInstance {
@Inject
User user;
@Inject
public SingleInstance() {
DaggerApplicationComponent.create().inject(this);
Log.i("TAG", "SingleInstance === " + user);
}
}
public class User {
//自定义的类通过@Inject注解修饰,在使用的地方使用@Inject初始化时,dagger会去找被@Inject修饰的类进行初始化。
@Inject
public User() {
}
}
@Component
public interface ApplicationComponent {
//指的将对象注入到那个地方,这里指的注入到MainActivity
void inject(MainActivity activity);
//指定将对象注入到什么位置,这里值注入到SingleInstance中
void inject(SingleInstance activity);
}
//TODO 被注入的类
public class MainActivity extends AppCompatActivity {
@Inject
SingleInstance instance;
@Inject
User user;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerApplicationComponent.create().inject(this);
Log.i("TAG", "instance == " + instance);
Log.i("TAG", "user == " + user);
}
}
2. 小结
- 在需要注入的地方通过
@Inject
注解进行标记。 @Component
修饰的是一个接口,并在该接口中提供一个将对象注入到哪里的方法。示例中为注入MainActivity
和SingleInstance
两个类中。- 需要在自定义类的构造函数通过
@Inject
注解进行修饰。 - 关键一步是将Component注入到目标类中,在需要实现注入的地方调用由
@Component
修饰的接口生成的对应的类。名字规则为Dagger+被@Component修饰的接口名
代码为DaggerApplicationComponent.create().inject(this);
。
2. 第二种实现方式
第三方库可以Module+主Component的方式实现。该种方式解决对第三方库的初始化。
@Module
public class HttpModule {
//TODO 在module提供实例
@NetScope
@Provides
String providerUrl() {
return "http://www.baidu.com";
}
@NetScope
@Provides
GsonConverterFactory providerGsonConverterFactory() {
return GsonConverterFactory.create();
}
@NetScope
@Provides
RxJava2CallAdapterFactory providerRxjava2CallAdapterFactory() {
return RxJava2CallAdapterFactory.create();
}
/**
* 1. 这里可以通过作用域限制实例使用的范围,这里的作用域必须和自己的Component使用的一样。
* 2. 一个Component只能有一个作用域修饰符。
*
* @return
*/
@NetScope
@Provides
OkHttpClient providerOkHttpClient() {
return new OkHttpClient.Builder()
//TODO 这里可以添加各种拦截器
.build();
}
@NetScope
@Provides
Retrofit providerRetrofit(String url,
OkHttpClient okHttpClient,
GsonConverterFactory gsonConverterFactory,
RxJava2CallAdapterFactory rxJava2CallAdapterFactory) {
return new Retrofit.Builder()
.baseUrl(url)
.client(okHttpClient)
.addConverterFactory(gsonConverterFactory)
.addCallAdapterFactory(rxJava2CallAdapterFactory)
.build();
}
@NetScope
@Provides
ApiService providerApiService(Retrofit retrofit) {
return retrofit.create(ApiService.class);
}
}
@Module
public class DaoModule {
@Name01
@Provides
Student providerStudent01() {
return new Student("tom01");
}
@Name02
@Provides
Student providerStudent02() {
return new Student("tom02", 20);
}
@Named("threeParam")
@Provides
Student providerStudent03() {
return new Student("tom03", 20, 1);
}
}
//NetScope这里的直接是为了限制其作用域
@NetScope
@Component(modules = {HttpModule.class,DaoModule.class})//装载多个Module
public interface HttpComponent {
void inject(MainActivity activity);
}
//被注入的类
public class MainActivity extends AppCompatActivity {
@Inject
ApiService apiService;
@Inject
ApiService apiService2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerHttpComponent.builder()
.build()
.inject(this);
Log.i(" TAG", "apiService === " + apiService);
Log.i(" TAG", "apiService2 === " + apiService2);
}
}
小结
- 通过Module提供了创建实例的方法。这里的
@NetScope
用于限制了创建实例的作用域。 providerRetrofit方法
中的参数是由其他几个方法提供的,如果没有提供@Providers
修饰的方法提供实例外,Dagger2会去找被@Inject
修饰的构造方法创建实例,如果都没有提供方法参数的实例则会报错。- 如果相同的类型创建不同的对象可以使用
@Named
注解解决. @NetScope
注解用来使用限定作用域。
3. 第三种实现方式
通过多组件实现相互依赖并提供实例。
//提供了全局的组件
@Component(modules = UserModule.class)
public interface ApplicationComponent {
User createUser();//通过这种方式需要将UserModule中的参数暴露出来,需要提供要暴露出来的相关方法。
// HttpComponent createHttpComponent();
}
//提供基础的实例
@BaseHttpScope
@Component(modules = BaseHttpModule.class, dependencies = ApplicationComponent.class)
public interface BaseHttpComponent {
//TODO 在其他子组件需要依赖时,需要将对应的方法暴露出来
Retrofit providerRetrofit();
}
//这里依赖了BaseHttpComponent组件中提供的实例
@NetScope
@Component(modules = ApiServiceModule.class, dependencies = BaseHttpComponent.class)
public interface ApiServiceComponent {
void inject(MainActivity activity);
}
//具体的实现注入的地方的初始化
public class MainActivity extends AppCompatActivity {
@Inject
ApiService apiService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerApiServiceComponent.builder()
.baseHttpComponent(DaggerBaseHttpComponent.builder()
.applicationComponent(DaggerApplicationComponent.create())
.build()).build()
.inject(this);
Log.i("TAG", "apiService == " + apiService);
}
}
小结
- 这里需要注意的是
ApiServiceComponent
组件依赖BaseHttpComponent
组件,BaseHttpComponent
组件以来的是ApplicationComponent
组件,结果就是在注入的地方如
DaggerApiServiceComponent.builder()
.baseHttpComponent(DaggerBaseHttpComponent.builder()
.applicationComponent(DaggerApplicationComponent.create())
.build()).build()
.inject(this);
- 需要被子组件使用的实例需要在
XXComponent
中暴露出来,如果没有暴露出来会去找被@Inject修饰的构造方法
创建实例,如果没有找到则会报错。不能提供对应的实例。
4. 第四种实现方式
跟上面多个Component
提供创建实例时,如果在子组件中需要使用父组件中提供的实例,父组件需要手动暴露出提供对应实例的方法。
@Module
public class ApiServiceModule {
//TODO 在module提供实例
@NetScope
@Provides
String providerUrl() {
return "http://www.baidu.com";
}
@NetScope
@Provides
GsonConverterFactory providerGsonConverterFactory() {
return GsonConverterFactory.create();
}
@NetScope
@Provides
RxJava2CallAdapterFactory providerRxjava2CallAdapterFactory() {
return RxJava2CallAdapterFactory.create();
}
/**
* 1. 这里可以通过作用域限制实例使用的范围,这里的作用域必须和自己的Component使用的一样。
* 2. 一个Component只能有一个作用域修饰符。
*
* @return
*/
@NetScope
@Provides
OkHttpClient providerOkHttpClient() {
return new OkHttpClient.Builder()
//TODO 这里可以添加各种拦截器
.build();
}
@NetScope
@Provides
Retrofit providerRetrofit(String url,
OkHttpClient okHttpClient,
GsonConverterFactory gsonConverterFactory,
RxJava2CallAdapterFactory rxJava2CallAdapterFactory) {
return new Retrofit.Builder()
.baseUrl(url)
.client(okHttpClient)
.addConverterFactory(gsonConverterFactory)
.addCallAdapterFactory(rxJava2CallAdapterFactory)
.build();
}
@NetScope
@Provides
ApiService providerApiService(Retrofit retrofit) {
return retrofit.create(ApiService.class);
}
}
@NetScope
@Subcomponent(modules = ApiServiceModule.class)
public interface ApiServiceComponent {
@Subcomponent.Factory
interface Factory {
ApiServiceComponent create();
}
void inject(MainActivity activity);
}
@Module(subcomponents = ApiServiceComponent.class)
public class ApiServiceComponentModule {
}
@Component(modules = {ApiServiceComponentModule.class})
public interface ApplicationComponent {
//这里在主组件中需要把子组件暴露出来
ApiServiceComponent.Factory createApiServiceComponent();
}
public class MainActivity extends AppCompatActivity {
@Inject
ApiService apiService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerApplicationComponent.create()
.createApiServiceComponent()
.create()
.inject(this);
Log.i("TAG", "apiService == " + apiService);
}
}
小结
- 这里需要注意的一点是SubComponent装载到主组件中时需要使用一个Module链接。
其他几个使用方法Binds和Lazy 参考demo app05
@Module
public abstract class DaoModule {
/**
* 这里的参数类型决定了调用哪一个实现方法
*
* @param impl01
* @return
*/
@Binds
public abstract BInterface bindBInterface01(Impl01 impl01);
@Provides
static Impl01 providerBInterface01() {
return new Impl01();
}
@Provides
static Impl02 providerBInterface02() {
return new Impl02();
}
}
public class MainActivity extends AppCompatActivity {
@Inject
BInterface impl01;
@Inject
Lazy<BInterface> impl02;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerApplicationComponent.create()
.inject(this);
Log.i("TAG", "impl01 === " + impl01.getClass().getSimpleName());
Log.i("TAG", "impl02 === " + impl02.getClass().getSimpleName());
Log.i("TAG", "impl02 impl02.get()=== " + impl02.get().getClass().getSimpleName());
}
}
参考资料
demo地址
作者:yanghai
链接:https://juejin.cn/post/7161042640048226312
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
链接:https://juejin.cn/post/7161042640048226312
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。