简单总结一下 方便日后查询
Dagger2是为了解决对象依赖关系而生的依赖注入框架 目的是为了降低代码耦合 它会在编译后自动为被inject的类添加所需要new出对应对象的代码
用大白话说
就比如
@Inject
User user;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_c);
DaggerCActivityComponent.builder().cUserModule(new CUserModule()).build().inject(this);
TextView tv = (TextView) findViewById(R.id.tv);
tv.setText(user.toString());
}
这里先@inject User user 看到这个 意味着我们下面的代码 等会如果哪里要用到这个user 实例了 就不需要重新new了 Dagger2会在编译的时候自动帮我们new出来
在项目中引入Dagger2需要修改两个地方的gradle文件,首先是project的gradle文件,修改成如下样子:
dependencies {
classpath 'com.android.tools.build:gradle:2.1.0'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
然后修改module的gradle文件:
apply plugin: 'com.neenbedankt.android-apt'
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:24.1.1'
compile 'com.google.dagger:dagger:2.6'
apt 'com.google.dagger:dagger-compiler:2.6'
compile 'com.squareup.picasso:picasso:2.5.2'
}
这里有几个地方需要说一下,首先Dagger2我们可以直接在jCenter中搜索到的,可以搜到之后直接添加,那么和Dagger2有关的是两个文件:
compile 'com.google.dagger:dagger:2.6'
apt 'com.google.dagger:dagger-compiler:2.6'
但是这两个一个用了compile一个用了apt,使用apt表示该引用类库只在编译的时候起作用,在打包的时候并不会打包到apk中去。
@Module
public class UserModule {
@Provides
@Singleton
User providesUser() {
return new User();
}
}
povidesUser() 方法返回了一个User对象
就在Module里被@Provides修饰的方法里定义
这里providersUser()方法刚好返回的是User对象 方法体很简单就是new User();
所以当Activity在用到User对象的时候,它就知道,我需要去Module里找对应的生成方法了,找到对应的Module 后,再在Module里找被@Provides修饰的方法,这个方法就为Dragger2提供了构建新对象的具体方法
4@Component
看到了@Module和@provides之后 还有一个疑问 就是 我知道被inject之后 一旦需要用到它的实体 我会到modules里面找 但Dagger2里 modules并不止一个
事实上 Dagger2允许你自定义无穷多的Modules 只要一个类里 有provides方法 然后被@Modules修饰 它就算是一个Module 。
那么多的Modules 如何告诉Dagger去那个里面找 这就需要用到一个新的注解 叫做@Component
一个Component 就类似一个注射器 他把药物 Modules 和 病人 (使用了依赖对象的类 比如这里片头的Activity )联系在了一起
他的定义方式很简单@Singleton
@Component(modules = UserModule.class)
public interface ActivityComponent {
void inject(MainActivity activity);
}
先用@Component注解修饰 告诉Dragger2这是一个组件(注射器),后面(modules=xxxModule.class , yyyModule.class...)告诉这个注射器可以打哪几种药物,组件都是接口,接口中定义了inject方法,这里的inject方法中需要传入一个病人对象,比如这里传入的是MainActivity ,这样一来,一个注射器就定义好了,他把Modules和注入的对象联系在一起了,这里可以定义多个带有不同参数的jnject方法 比如
@UserScope
@Component(modules = UserModule.class)
public interface ActivityComponent {
void inject(MainActivity activity);
void inject(BActivity activity);
}
这涉及到下面要说的 @scope注解了
5@scope
顾名思义 他是用来定义作用域的
前面用的@singleton 是系统自带的一个scope 被它修饰的类它意味着在整个项目中只有一个实体 ,也就是全局单利 模式,在实际开发过程中,除了全局单例,更常见的是局部单例,比如
以下参考博主
http://blog.csdn.net/u012702547/article/details/52213706
我们有三个Activity,MainActivity,BActivity和CActivity,我们想让MainActivity和BActivity共享同一个实例,而让CActivity获取另外一个实例,这又该怎么实现呢?在Dagger2中,我们可以通过自定义Scope来实现局部单例。
首先让我们先来定义一个局部作用域:@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface UserScope {
}
然后在我们的UserModule和ActivityComponent中应用该局部作用域:
@Module
public class UserModule {
@Provides
@UserScope
User providesUser() {
return new User();
}
}
@UserScope
@Component(modules = UserModule.class)
public interface ActivityComponent {
void inject(MainActivity activity);
void inject(BActivity activity);
}
请大家注意,我的ActivityComponent作为一个注入器只可以向MainActivity和BActivity两个Activity中注入依赖,不可以向CActivity中注入依赖。最后,要让该局部作用域产生单例效果,需要我们在自定义的Appliation类中来初始化这个Component,如下:
public class MyApp extends Application {
ActivityComponent activityComponent;
@Override
public void onCreate() {
super.onCreate();
activityComponent = DaggerActivityComponent.builder().userModule(new UserModule()).build();
}
ActivityComponent getActivityComponent(){
return activityComponent;
}
}
接下来我们在MainActivity和BActivity中注入依赖,MainActivity如下:
@Inject
User user;
@Inject
User user2;
private TextView tv;
private TextView tv2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// DaggerActivityComponent.builder().userModule(new UserModule()).build().inject(this);
((MyApp) getApplication()).getActivityComponent().inject(this);
tv = ((TextView) findViewById(R.id.tv));
tv2 = ((TextView) findViewById(R.id.tv2));
tv.setText(user.toString());
tv2.setText(user2.toString());
}
BActivity如下:
@Inject
User user;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_b);
((MyApp) getApplication()).getActivityComponent().inject(this);
TextView tv = (TextView) findViewById(R.id.tv);
tv.setText(user.toString());
}
那么如果我还想在CActivity中使用User对象该怎么办呢?再来一个CUserModule和CActivityComponent
CUserModule如下:
@Module
public class CUserModule {
@Provides
User providesUser() {
return new User();
}
}
这里没有再著名单例
CActivityComponent如下:
@Component(modules = CUserModule.class)
public interface CActivityComponent {
void inject(CActivity activity);
}
在CActivity中注入依赖:
@Inject
User user;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_c);
DaggerCActivityComponent.builder().cUserModule(new CUserModule()).build().inject(this);
TextView tv = (TextView) findViewById(R.id.tv);
tv.setText(user.toString());
}
运行结果如下:
可以看到,MainActivity和BActivity是同一个实例,而CActivity则是另外一个实例。
@UserScope在这里到底起了什么作用?我引用网上一段话:
以下文字来源:http://blog.csdn.net/u012943767/article/details/51941872
Scope的使用,如何实现单例?
这个迷之Scope也是有点难以理解,我们在哪里使用到了Scope呢。在我们的AppComponent中添加了一个注解为@Singleton,@Singleton就是一个Scope,据说可以实现单例哟。。。难道这样就实现了单例模式?我刚刚开始是这样理解的。直到仔细的看了几遍这篇文章我才知道并不是这样的。
事实上@Sinleton中并没有创建单例的能力,那么AppComponent中提供的依赖注入是如何实现单例的呢。其实这个原理很贱单。
首先Module提供了创建实例的方法,接着AppComponent中对Module进行管理,最后AppComponent在自定义Applicaiton中被实例化了一次。
这个实例化了一次是最重要的呀。仅仅被实例化了一次,那不就是单例么。就是这么简单呀。
可能有些童靴当时就不乐意了,那既然这样都已经实现了单例,那么这个@Singltop还要来何用?不是多此一举吗。
其实@Singletop还有有一些作用的,首先一方面能让你直面的了解到这是一个单例,其次这个@Singletop能够更好的管理Modlue和Component之间的关系。
Dagger2需要保证Component和Module是匹配的,就需要用到这个注解。