注册

Dagger2四种使用方式

1. 什么是Dagger2


Dagger2是用来解决对象之间的高度耦合的框架。介绍Dagger2四种方式实现。


image.png


具体的四种使用场景


0. 配置


app模块下的build.gradle
dependencies {
//...其他依赖信息
implementation 'com.google.dagger:dagger:2.44'
annotationProcessor 'com.google.dagger:dagger-compiler:2.44'
}

1. 第一种实现方式


自己实现的代码可以在代码的构造函数上通过@Inject修饰,实现代码注入,如下:


image.png


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. 小结


  1. 在需要注入的地方通过@Inject注解进行标记。
  2. @Component修饰的是一个接口,并在该接口中提供一个将对象注入到哪里的方法。示例中为注入MainActivitySingleInstance两个类中。
  3. 需要在自定义类的构造函数通过@Inject注解进行修饰。
  4. 关键一步是将Component注入到目标类中,在需要实现注入的地方调用由@Component修饰的接口生成的对应的类。名字规则为Dagger+被@Component修饰的接口名代码为DaggerApplicationComponent.create().inject(this);

2. 第二种实现方式


第三方库可以Module+主Component的方式实现。该种方式解决对第三方库的初始化。


image.png


@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);

}
}


小结


  1. 通过Module提供了创建实例的方法。这里的@NetScope用于限制了创建实例的作用域。
  2. providerRetrofit方法中的参数是由其他几个方法提供的,如果没有提供@Providers修饰的方法提供实例外,Dagger2会去找被@Inject修饰的构造方法创建实例,如果都没有提供方法参数的实例则会报错。
  3. 如果相同的类型创建不同的对象可以使用@Named注解解决.
  4. @NetScope注解用来使用限定作用域。

3. 第三种实现方式


通过多组件实现相互依赖并提供实例。


image.png


//提供了全局的组件
@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);

}
}

小结



  1. 这里需要注意的是ApiServiceComponent组件依赖BaseHttpComponent组件,BaseHttpComponent组件以来的是ApplicationComponent组件,结果就是在注入的地方如

 DaggerApiServiceComponent.builder()
.baseHttpComponent(DaggerBaseHttpComponent.builder()
.applicationComponent(DaggerApplicationComponent.create())
.build()).build()
.inject(this);


  1. 需要被子组件使用的实例需要在XXComponent中暴露出来,如果没有暴露出来会去找被@Inject修饰的构造方法创建实例,如果没有找到则会报错。不能提供对应的实例。

4. 第四种实现方式


跟上面多个Component提供创建实例时,如果在子组件中需要使用父组件中提供的实例,父组件需要手动暴露出提供对应实例的方法。


image.png



@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);
}
}

小结



  1. 这里需要注意的一点是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
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册