Dagger2系列博客
转载请标明出处:
https://blog.csdn.net/u011035026/article/details/83040030
1、简介
- Dagger2是Java和Android的快速依赖注入器,是依赖注入的编译时框架。它不使用反射或运行时字节码生成,在编译时进行所有分析,并生成纯Java源代码。一般的IOC框架都是通过反射来实现的,但Dagger2作为Android端的IOC框架,为了不影响性能,它是通过apt动态生成代码来实现的,通俗来说就是通过apt注解的方式在编译时注入代码。其主要作用就是解耦和管理实例对象。
依赖的提供方(两种方式):
- 使用@Inject注解构造器的类。可使用在自己可以修改源码的类中。
- 使用@Module注解包含提供依赖方法的类,使用@Provide方法注解提供依赖的方法。用在提供没有修改源码权限的类的依赖。
依赖的需求方(两种方式):
- 正常的类,使用了@Inject注解了成员变量的类。这里注入依赖需要自己触发。
- @Inject注解构造器的类。这里@Inject注解的成员变量和构造器参数都会去框架中去找,这个过程是编译时自动完成的。这些类既是依赖的需求方也是依赖的提供方。
依赖注入器:
- 使用@Component或者@SubComponent注解的接口或者抽象类
- 描述可以提供哪些依赖
- 描述可以注入到哪些依赖需求方
- 管理依赖的生命周期
2、注解跟对应具体示例
(1)@Inject
- @Inject标记需要依赖的变量,以此告诉Dagger2为它提供依赖;
- @Inject标记构造函数,Dagger2通过@Inject注解可以在需要这个类实例的时候来找到这个构造函数并把相关实例构造出来,以此来为被@Inject标记了的变量提供依赖;
(2)@Module
- @Module用于标注提供依赖的类。
- 你可能会有点困惑,上面不是提到用@Inject标记构造函数就可以提供依赖了么,为什么还需要@Module?很多时候我们需要提供依赖的构造函数是第三方库的,我们没法给它加上@Inject注解,又比如说提供以来的构造函数是带参数的,如果我们之所简单的使用@Inject标记它,那么他的参数又怎么来呢?@Module正是帮我们解决这些问题的。
(3)@Provides
- @Provides用于标注Module所标注的类中的方法,该方法在需要提供依赖时被调用,从而把预先提供好的对象当做依赖给标注了@Inject的变量赋值;
(4)@Component
- @Component用于标注接口,是依赖需求方和依赖提供方之间的桥梁。被Component标注的接口在编译时会生成该接口的实现类(如果@Component标注的接口为CarComponent,则编译期生成的实现类为DaggerCarComponent),我们通过调用这个实现类的方法完成注入;
// 注意:这是上述四个注解的正常使用示例
// 具体类,这里仅仅只是为了模拟
public class HttpRequest {
// 可以假设这是网络请求相关的类
}
// Module,依赖提供方
@Module
public class HttpModule {
@Provides
public HttpRequest provideHttpRequest(){
return new HttpRequest();
}
}
// Component,依赖注入容器
@Component {modules = {HttpModule.class}}
public interface HttpComponent {
void injectActivity(TestActivity activity);
}
// 依赖需求方
public class TestActivity extends AppCompatActivity {
@Inject
HttpRequest httpRequest;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMyComponent.builder()
.httpModule(new HttpModule())
.build()
.injectActivity(this);
Log.i("Test", httpRequest.hashCode() + "");
}
}
(5)@Singleton(不推荐使用)
- @Singleton其实就是一个通过@Scope定义的注解,我们一般通过它来实现全局单例。但实际上它并不能提前全局单例,是否能提供全局单例还要取决于对应的Component是否为一个全局对象。
// 具体类,这里仅仅只是为了模拟
public class HttpRequest {
// 可以假设这是网络请求相关的类
}
// Module,依赖提供方
@Singleton
@Module
public class HttpModule {
@Singleton
@Provides
public HttpRequest provideHttpRequest(){
return new HttpRequest();
}
}
// Component,依赖注入容器
@Singleton
@Component {modules = {HttpModule.class}}
public interface HttpComponent {
void injectActivity(TestActivity activity);
}
// 依赖需求方
public class TestActivity extends AppCompatActivity {
@Inject
HttpRequest httpRequest1;
@Inject
HttpRequest httpRequest2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMyComponent.builder()
.httpModule(new HttpModule())
.build()
.injectActivity(this);
Log.i("Test", httpRequest1.hashCode() + "");
Log.i("Test", httpRequest2.hashCode() + "");
}
}
(6)@Scope
- @Scope同样用于自定义注解,我能可以通过@Scope自定义的注解来限定注解作用域,实现局部或全局的单例;
// 具体类,这里仅仅只是为了模拟
public class HttpRequest {
// 可以假设这是网络请求相关的类
}
// 推荐通过@Scope自定义单例
@Scope
@Documented
@Retention(RUNTIME)
public @interface AppScope {
}
// Application
public class MyApplication extends Application {
private MyComponent myComponent;
@Override
public void onCreate() {
super.onCreate();
myComponent= DaggerMyComponent.builder()
.httpModule(new HttpModule())
.build();
}
public MyComponent getAppComponent(){
return myComponent;
}
}
// Module,依赖提供方
@AppScope
@Module
public class HttpModule {
@AppScope
@Provides
public HttpRequest provideHttpRequest(){
return new HttpRequest();
}
}
// Component,依赖注入容器
@AppScope
@Component {modules = {HttpModule.class}}
public interface MyComponent {
void injectActivity(TestActivity activity);
}
// 依赖需求方
public class TestActivity extends AppCompatActivity {
@Inject
HttpRequest httpRequest1;
@Inject
HttpRequest httpRequest2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((MyApplication) getApplication()).getAppComponent()
.injectActivity(this);
Log.i("Test", httpRequest1.hashCode() + "");
Log.i("Test", httpRequest2.hashCode() + "");
}
}
(7)dependencies
- dependencies可以用来解决组件依赖,如果要使用需要注意:(a)多个组件之间的scope不能相同;(b)没有scope的不能依赖有scope的组件。
// 具体类,这里仅仅只是为了模拟
public class HttpRequest {
// 可以假设这是网络请求相关的类
}
public class Presenter {
// 可以假设这是Presenter相关的类
}
// Module,依赖提供方
@AppScope
@Module
public class HttpModule {
@AppScope
@Provides
public HttpRequest provideHttpRequest(){
return new HttpRequest();
}
}
@UserScope
@Module
public class PresenterModule {
@UserScope
@Provides
public Presenter providePresenter(){
return new Presenter();
}
}
// Component,依赖注入容器
@AppScope
@Component(modules = {HttpModule.class},dependencies = {PresenterComponent.class})
public interface MyComponent {
void injectActivity(TestActivity activity);
}
@UserScope
@Component(modules = {PresenterModule.class})
public interface PresenterComponent {
public Presenter providePresenter();
}
// 依赖需求方
public class TestActivity extends AppCompatActivity {
@Inject
HttpRequest httpRequest;
@Inject
Presenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMyComponent.builder()
.presenterComponent(DaggerPresenterComponent.builder()
.presenterModule(new PresenterModule())
.build())
.httpModule(new HttpModule())
.build()
.injectActivity(this);
Log.i("Test", httpRequest.hashCode() + "");
Log.i("Test", "presenter=" + presenter.hashCode());
}
}
(8)@Subcomponent(不推荐使用)
- @Subcomponent用于通过子组件的方式解决组件依赖,不推荐,因为被子组件修饰的Model类无法传递参数)。
// 具体类,这里仅仅只是为了模拟
public class HttpRequest {
// 可以假设这是网络请求相关的类
public String baseUrl;
public HttpRequest(){}
public HttpRequest(String baseUrl){
this.baseUrl=baseUrl;
}
}
public class Presenter {
// 可以假设这是Presenter相关的类
}
// Module,依赖提供方
@Module
public class HttpModule {
private String baseUrl;
public HttpModule(String baseUrl){
this.baseUrl=baseUrl;
}
@Provides
public HttpRequest provideHttpRequest(){
return new HttpRequest(baseUrl);
}
}
@Module
public class PresenterModule {
@Provides
public Presenter providePresenter(){
return new Presenter();
}
}
// Component,依赖注入容器
@Component(modules = {HttpModule.class})
public interface HttpComponent {
PresenterComponent buildPresenterComponent();
}
@Subcomponent(modules = {PresenterModule.class})
public interface PresenterComponent {
void injectActivity(TestActivity activity);
}
// 依赖需求方
public class TestActivity extends AppCompatActivity {
@Inject
HttpRequest httpRequest;
@Inject
Presenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String baseUrl = "www.baidu.com"
DaggerHttpComponent.builder()
.httpModuleRequest(new HttpModule(baseUrl)).build()
.buildPresenterComponent()
.injectActivity(this);
Log.i("Test", httpRequest.hashCode() + "");
Log.i("Test", "presenter=" + presenter.hashCode());
}
}
(9)@Named
- @Named可以做到标识在同一个Module中提供相同类实例对象而造成的依赖注入迷失问题,通俗易懂来讲就是起别名。
// 具体类,这里仅仅只是为了模拟
public class HttpRequest {
// 可以假设这是网络请求相关的类
public String baseUrl;
public HttpRequest(){}
public HttpRequest(String baseUrl){
this.baseUrl=baseUrl;
}
}
// Module,依赖提供方
@Module
public class HttpModule {
private ArrayList<String> baseUrlList;
public HttpModule(ArrayList<String> baseUrlList){
this.baseUrlList=baseUrlList;
}
@Named("base1")
@Provides
public HttpRequest provideHttpRequest1(){
return new HttpRequest(baseUrlList.get(0));
}
@Named("base2")
@Provides
public HttpRequest provideHttpRequest2(){
return new HttpRequest(baseUrlList.get(1));
}
}
// Component,依赖注入容器
@Component(modules = {HttpModule.class})
public interface HttpComponent {
void injectActivity(TestActivity activity);
}
// 依赖需求方
public class TestActivity extends AppCompatActivity {
@Inject
@Named("base1")
HttpRequest httpRequest1;
@Inject
@Named("base2")
HttpRequest httpRequest2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String baseUrl1 = "www.baidu.com";
String baseUrl2 = "www.taobao.com";
ArrayList<String> urlList = new ArrayList<>();
urlList.add(baseUrl1);
urlList.add(baseUrl2);
DaggerHttpRequestComponent.builder()
.httpModule(new HttpModule(urlList))
.injectActivity(this);
Log.i("Test", httpRequest1.baseUrl + "");
Log.i("Test", httpRequest2.baseUrl + "");
}
}
(10)@Qulifier
- @Qulifier作用跟@Named非常类似,只不过@Named是模板而已。
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Named {
/** The name. */
String value() default "";
}