本文代码:
[DaggerExample]: https://github.com/zrfzhouruifeng163/DaggerExample
Dagger2是个啥?
一个依赖注入框架。(f....这是刷?哥们谷度吧)
Dagger2能解决啥问题?
进一步解耦
解耦? 看下下面的强耦合性代码
public class C {
public void methodC() {
}
}
public class Example01Activity extends AppCompatActivity {
C c;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_example01);
c = new C();//随便new
c.methodC();
}
}
Example01Activity强烈依赖C,如果C的构造方法发生变化,onCreate内的代码得发生变化。
直白的说即是,Example01Activity里new了C,dagger2作用是解耦,实际就是不让Example01Activity里newC 又能给C的实例赋值。
上升一步高度,在这里强耦合的描述是,调用者调用被调用者,Example01Activity调用C ,Example01Activity是调用者,C是被调用者,在调用者内直接new被调用者。使用dagger2后,new的过程被转移到dagger2中了,dagger2再把对象注入到Example01Activity中。
dagger2处理后,代码如下:-----example01
public class C {
@Inject
public C() {
}
public void methodC() {
Log.e("c","ccc");
}
}
@Component
public interface Example01ActivityComponent {
void inject(Example01Activity activity);
}
public class Example01Activity extends AppCompatActivity {
@Inject
C c;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_example01);
DaggerExample01ActivityComponent.create().inject(this);
//这里的c没有new,就能直接使用了 啦啦啦
c.methodC();
}
}
冒然一看,上边代码貌似增加了代码量,其实真的是增加了代码量,但从逻辑上来看,的确没有在调用者中new了,勉强说是解耦了吧,虽然看起来没什么niao用。后续慢慢思考!
Dagger2的环境配置
作为一名安卓开发者,当前配置是
AndroidStudio 3.0.1
Android Plugin Version 2.3.1
Gradle version 3.3
----------------------------------------------
app下build.gradle
dependencies内增加:
compile 'com.google.dagger:dagger:2.14.1'
annotationProcessor 'com.google.dagger:dagger-compiler:2.14.1'
版本可以自己更改为最新,我就暂时用2.14.1了
常用的api清单
@Inject
@Component
@Module
@Qualifier
@Named
@Scope
@Singleton
@Lazy
@Provides
@IntoSet
@ElementsIntoSet
@IntoMap
大概有个印象,至于作用,后续慢慢说
有个前提
大家最好对注解和依赖注入有个了解,具体的可以自己谷度。
先从Inject和Component开始
@Inject 可以标注在三个地方
1.属性,表示我要往这个实例中注入对象,这是注入的目标。注意,该属性为非private的。
2.构造方法,表示我要用这个构造方法去生成对象,然后通过component注入到被Inject标注的属性上。注意,一个类中,只能有一个构造方法被标注。
3.方法上,可以理解为属性的set方式,也是注入的目标。
@Component 用该注解标注的接口,就是一个注入器,用于表示要往哪些类中注入,是一个入口。接口的命名方式:目标类+Component
@Inject标注在属性和构造方法上,实例代码如下 ----- example02
public class Book {
//标注在构造方法上,表示我要用这个构造方法去生成对象
@Inject
public Book() {
}
public void read(){
Log.e("book","read 水壶传");
}
}
/**
* 标注在接口上,表示这是一个注入器,针管儿,要打针啦
* 要给PersonActivity打针,所以接口命名为PersonActivityComponent
*/
@Component
public interface PersonActivityComponent {
//表示给哪个类注入,这里表示要给PersonActivity打针
void inject(PersonActivity activity);
}
public class PersonActivity extends AppCompatActivity {
//标注在属性上,表示我要往这个属性内注入对象,记得是非private的
@Inject
Book book;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_person);
//在写这里之前记得先Build-make project下,在编译期内会生成一些代码
//DaggerPersonActivityComponent就是在make后生成的,不make,是找不到这个类的,命名规则是:Dagger+component接口名
//PersonActivity + Component
//Dagger + PersonActivityComponent
//清楚了没
//言归正传,这里的作用是要给这个类注入内容
DaggerPersonActivityComponent.create().inject(this);
//直接调用方法就行了
book.read();
}
}
@Inject标注在方法上,实例代码如下 ------example03
public class Book {
//标注在构造方法上,表示我要用这个构造方法去生成对象
@Inject
public Book() {
}
public void read(){
Log.e("book","read 三国演义");
}
}
/**
* 标注在接口上,表示这是一个注入器,针管儿,要打针啦
* 要给Person2Activity打针,所以接口命名为Person2ActivityComponent
*/
@Component
public interface Person2ActivityComponent {
//表示给哪个类注入,这里表示要给PersonActivity打针
void inject(Person2Activity activity);
}
public class Person2Activity extends AppCompatActivity {
private Book book;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_person);
//在写这里之前记得先Build-make project下,在编译期内会生成一些代码
//DaggerPerson2ActivityComponent就是在make后生成的,不make,是找不到这个类的,命名规则是:Dagger+component接口名
//Person2Activity + Component
//Dagger + Person2ActivityComponent
//清楚了没
//言归正传,这里的作用是要给这个类注入内容
DaggerPerson2ActivityComponent.create().inject(this);
//直接调用方法就行了
book.read();
}
//标注在方法上,类似set 表示我要往这个属性内注入对象,记得这里的属性可以是private的
@Inject
public void setBook(Book book){
this.book = book;
//这里就获取到了this,可以直接使用this了
this.load();
}
//对象的方法
public void load(){
Log.e("load","hello world");
}
}
@Inject在属性和方法上有啥异同?
1.二者都是给属性注入对象
2.标注在方法上,在方法内可以使用this关键字了,因为肯定是在调用完类的构造方法后才可以使用标注的方法,这时候当然有this了
可以想象下,标注在方法和属性上,可以同时使用吗?
of course --yes ------example04 如下:
public class Apple {
//标注在构造方法上,表示我要用这个构造方法去生成对象
@Inject
public Apple() {
}
public void eat(){
Log.e("apple","eat bugs");
}
}
public class Book {
//标注在构造方法上,表示我要用这个构造方法去生成对象
@Inject
public Book() {
}
public void read(){
Log.e("book","read 三国演义");
}
}
@Component
public interface Person3ActivityComponent {
void inject(Person3Activity activity);
}
public class Person3Activity extends AppCompatActivity {
@Inject
Book book;
private Apple apple;
@Inject
Apple apple2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_person3);
DaggerPerson3ActivityComponent.create().inject(this);
book.read();
apple.eat();
apple2.eat();
}
@Inject
public void setApple(Apple apple) {
this.apple = apple;
}
}
Please think another question ---component可以同时给多个类注入吗?
of course ----yes ------example05
public class Book {
//标注在构造方法上,表示我要用这个构造方法去生成对象
@Inject
public Book() {
}
public void read(){
Log.e("book","read 三国演义");
}
}
@Component
public interface Person4ActivityComponent {
//给Person4Activity打针
void inject(Person4Activity activity);
//给Person5Activity打针
void inject(Person5Activity activity);
}
public class Person4Activity extends AppCompatActivity {
@Inject
Book book;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_person4);
DaggerPerson4ActivityComponent.create().inject(this);
Log.e("tag","Person4Activity");
book.read();
}
}
public class Person5Activity extends AppCompatActivity {
@Inject
Book book;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_person5);
DaggerPerson4ActivityComponent.create().inject(this);
Log.e("tag","Person5Activity");
book.read();
Intent intent = new Intent(this,Person4Activity.class);
startActivity(intent);
}
}
再说@Module和@Provides
@Module:向 注入器 提供对象实例的类,想下@Inject作用在构造方法上,其作用就是向注入器提供构造对象的方法。@Module有相同的作用,只是换了一种方式,这是对@Inject的补充。
@Provides:与@Module配合使用的,标注在Module内的具体的提供对象的方法上。
描述个场景:
我们使用了两个类Apple和Book,但是Apple和Book分别来源于第三方的sdk,这时候 我们就没有办法在Apple和Book的构造上进行标注@Inject了,这时候又想使用dagger2 ,咋办呢,@Module来了。
看个实例代码----example06
//模拟来源于第三方sdk的类,不能修改其源码
public class Book {
public Book() {
}
public void read(){
Log.e("book","read 三国演义");
}
}
//模拟来源于第三方sdk的类,不能修改其源码
public class Apple {
public Apple() {
}
public void eat(){
Log.e("apple","eat bugs");
}
}
/**
* 表示向构造器提供对象的类
*/
@Module
public class MyModule {
//标注在方法上,表示具体的提供对象的方法,命名方式一般为:provide+具体要提供的类名
@Provides
Apple provideApple(){
return new Apple();//这里需要new了
}
//标注在方法上,表示具体的提供对象的方法
@Provides
Book provideBook(){
return new Book();//这里需要new了
}
}
//这里的modules=Mydule.class 表示我这个注入器,从MyModule中寻找提供对象实例的方法
@Component(modules = MyModule.class)
public interface ModuleActivityComponent {
void inject(ModuleActivity activity);
}
public class ModuleActivity extends AppCompatActivity {
@Inject
Apple apple;
@Inject
Book book;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_module);
DaggerModuleActivityComponent.create().inject(this);
apple.eat();
book.read();
}
}
描述下流程:
1.ModuleActivityComponent为入口,想要注入到目标类ModuleActivity中
2.发现ModuleActivity中有两个属性需要注入@Inject Apple 和@Inject Book
3.从哪儿找提供对象实例的的来源呢?发现component上有个modules=MyModule.class
4.去往Mymodule
5.找到了两个Provides方法,正好是provideApple 和 provideBook,ok,就这俩了
6.调用MyModule内的方法,然后给ModuleActivity中的俩属性注入实例。
OK,question,一个component可以多个module吗?
of course ---yes 实例代码如下 ------example07
//模拟来源于第三方sdk的类,不能修改其源码
public class Apple {
public Apple() {
}
public void eat(){
Log.e("apple","eat bugs");
}
}
//模拟来源于第三方sdk的类,不能修改其源码
public class Book {
public Book() {
}
public void read(){
Log.e("book","read 三国演义");
}
}
/**
* 表示向构造器提供Apple对象的类
*/
@Module
public class AppleModule {
//标注在方法上,表示具体的提供对象的方法
@Provides
Apple provideApple(){
return new Apple();//这里需要new了
}
}
/**
* 表示向构造器提供Book对象的类
*/
@Module
public class BookModule {
//标注在方法上,表示具体的提供对象的方法
@Provides
Book provideBook(){
return new Book();//这里需要new了
}
}
//多个module用这种方式
@Component(modules = {AppleModule.class,BookModule.class})
public interface Module01ActivityComponent {
void inject(Module01Activity activity);
}
public class Module01Activity extends AppCompatActivity {
@Inject
Apple apple;
@Inject
Book book;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_module01);
DaggerModule01ActivityComponent.create().inject(this);
apple.eat();
book.read();
}
}
OK,question again,对接口声明的字段标注@Inject和对接口实现类的构造标注@Inject,能实现注入吗?看下面的代码----example08
public interface IAnimal {
void bark();
}
public class Dog implements IAnimal {
//这里对接口实现类的构造进行标注
@Inject
public Dog() {
}
public void bark(){
Log.e("dog bark","汪汪汪");
}
}
public class AnimalActivity extends AppCompatActivity {
//这里对接口声明的字段标注
@Inject
IAnimal animal;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_animal);
DaggerAnimalActivityComponent.create().inject(this);
animal.bark();
}
}
@Component
public interface AnimalActivityComponent {
void inject(AnimalActivity activity);
}
The answer is NO. 会报错的,注入不了。
但是,接口的引用指向子类的对象,这是一种很常用的用法,该如何实现呢,---module啦,一切尽在code中。
public interface IAnimal {
void bark();
}
public class Dog implements IAnimal {
//这里不需要标注@Inject
public Dog() {
}
public void bark(){
Log.e("dog bark","汪汪汪");
}
}
public class Cow implements IAnimal {
//注意这里需要标注@Inject
@Inject
public Cow() {
}
@Override
public void bark() {
Log.e("cow bark","哞哞哞");
}
}
@Module
public class AnimalModule {
//方式一: 直接在提供的方法内new一个就行了 这时Dog的构造上不需要@Inject
// @Provides
// IAnimal provideAnimal(){
// return new Dog();//new new new
// }
//方式二:在接口实现类Cow的构造上@Inject ,在这里直接当参数传进来,即可
//这里在参数中有Cow,会去寻找是否有Cow实例的方法,发现Cow的构造上有@Inject 使用。
@Provides
IAnimal provideAnimal(Cow cow){
return cow;
}
}
@Component(modules = AnimalModule.class)
public interface Animal2ActivityComponent {
void inject(Animal2Activity activity);
}
public class Animal2Activity extends AppCompatActivity {
@Inject
IAnimal animal;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_animal2);
DaggerAnimal2ActivityComponent.create().inject(this);
animal.bark();
}
}
在上面的AnimalModule中列出了方式一和方式二,两个provide方法,大家应该注意到了我把方式一给注释了,why?因为放开后,运行会报错,这当然是废话,为什么报错呢?我的理解是,一方面provide的方法不要重名,尽管符合重载原则,另一方面,因为在dagger2中,component会寻找对象构造来源,这个来源通常是唯一的,上面的方式一二 ,两个方法都是构造IAnimal的,可以说component找到了两个来源,然后就不知道选择哪个了,就报错了。
怎么解决呢?
引出@Named和@Qualifier
作用:
1.标记在provide方法上,用于区分来源。
2.标记在字段上,表示使用哪个来源。
先说@Named,代码如下,----example10
public class Oriange implements IFruit{
@Inject
public Oriange() {
}
@Override
public void name() {
Log.e("name","oriange");
}
}
public class Banana implements IFruit{
@Override
public void name() {
Log.e("name","banananana");
}
}
public class Pear implements IFruit {
public String name = "China";
@Inject //注意构造方法上不能打@Named
public Pear() {
name = "China";
}
public Pear(String name) {
this.name = name;
}
@Override
public void name() {
Log.e("name",name);
}
}
@Module
public class FruitModule {
@Provides
@Named("banana")//打标记,标记来源,用于区分
IFruit provideBanana(){
return new Banana();
}
@Provides
@Named("oriange")//打标记,标记来源,用于区分
IFruit provideOriange(Oriange oriange){
return oriange;
}
@Provides
@Named("pear2")
Pear providePear(){
Log.e("from","module pear");
return new Pear("America");
}
}
@Component(modules = FruitModule.class)
public interface FruitActivityComponent {
void inject(FruitActivity activity);
}
public class FruitActivity extends AppCompatActivity {
@Inject
@Named("banana") //标记是用哪个来源进行注入
IFruit banana;
@Inject
@Named("oriange") //标记是用哪个来源进行注入
IFruit oriange;
@Inject //对应的是Pear中的构造方法上的@Inject 注意构造方法上不能打@Named
Pear pear1;
@Inject
@Named("pear2") //对应的是FruitModule中的方法
Pear pear2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fruit2);
DaggerFruitActivityComponent.create().inject(this);
banana.name();
oriange.name();
pear1.name();
pear2.name();
}
}
再说@Qualifier ,也是标记来源,@Named是通过字符串来唯一确定,而@Qualifier是通过定义注解来区分,具体做法是,定义一个注解,然后在该注解上标注@Qualifier,然后将该注解标注在构造器来源和@Inject标注的字段上。不同的来源定义不同的注解。
二者的区别是,Named需要手动去写这个唯一标示,Qualifier则是直接定义,省去了写字符串的过程,更加简洁。
代码如下----example11
public class Bird {
public String name;
public Bird(String name) {
this.name = name;
}
public void name(){
Log.e("name=",name);
}
}
/**
* 定义一个注解,并标注@Qualifier,这里定义的是标注parrot来源的注解
*/
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface ParrotQualifier {
}
/**
* 定义一个注解,并标注@Qualifier,这里定义的是标注sparrow来源的注解
*/
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface SparrowQualifier {
}
@Module
public class BirdModule {
//不同的来源标注不同的Qualifier,用于区分
@Provides
@SparrowQualifier //标注sparrow注解,表示这是sparrow对象的来源
Bird provideBird1(){
return new Bird("sparrow");
}
@Provides
@ParrotQualifier //标注parot注解,表示这是parrot对象的来源
Bird provideBird2(){
return new Bird("parrot");
}
}
@Component(modules = BirdModule.class)
public interface BirdActivityComponent {
void inject(BirdActivity activity);
}
public class BirdActivity extends AppCompatActivity {
@Inject
@SparrowQualifier //标注sparrow注解,表示要使用被SparrowQualifier标注的来源,注入到该字段
Bird sparrow;
@Inject
@ParrotQualifier //标注parrot注解,表示要使用被ParrotQualifier标注的来源,注入到该字段
Bird parrot;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bird);
DaggerBirdActivityComponent.create().inject(this);
sparrow.name();
parrot.name();
}
}
@Inject @Module @Component的工作流程
文字叙述:
1.component为入口
2.inject确定被注入的目标类(如XXXActivity)
3.在目标类中确认有哪些被@Inject标注的字段或方法需要被注入实例。
4.回到component,查看是否有module
5.有module
5.1查看module中是否有提供依赖的provide方法
5.2有提供依赖的provide方法
5.2.1 方法上没有参数,则直接利用这个方法创建对象,注入到目标字段
5.2.2 方法上有参数,那么此时该参数也是需要被注入的字段(等效于被@Inject标注了),那么此时就需要从步骤1的component开始,寻找能为此参数提供依赖的标注,一直找到为止,然后利用该参数所在的方法,创建对象,注入到目标字段中。
5.3没有提供依赖的provide方法,则从6.1开始
6.无module
6.1在各个类中寻找被@Inject标注的构造方法
6.2没有找到能提供依赖的被@Inject标注的构造方法,则报错,证明没有可以提供依赖的来源。
6.3找到了提供依赖的@Inject构造方法
6.4查看该构造方法上是否有参数
6.5构造上没有参数,则直接利用此构造创建对象,然后注入到目标字段上
6.6构造上有参数,那么此时该参数也是需要被注入的字段(等效于被@Inject标注了),那么此时就需要从步骤1的component开始,寻找能为此参数提供依赖的标注,一直找到为止,然后继续进行利用参数所在的构造函数进行创建对象,然后注入到目标字段上。
@Scope
scope有范围、余地的意思,被scope标注的类,在一定范围内能达到单例的效果,即只创建一次,多次使用都是同一个对象。
@Scope的源码如下:
@Target(ANNOTATION_TYPE)
@Retention(RUNTIME)
@Documented
public @interface Scope {}
ANNOTATION_TYPE 表示Scope只能标注在注解上。
需要注意:
1.@Scope是用于自定义注解的,只能标注在注解上。
2.被@Scope自定义出来的注解,是可以标注在类、方法和Component上的
Scope使用方式一:
Scope标注在类以及Component上
步骤:
1.使用@Scope自定义一个注解@MyScope
2.将@MyScope标注在类上
3.将@MyScope标注在Component上
4.使用Component进行注入实现即可
实例代码如下 ---example12
/**
* Scope只能标注在注解上
* 这里自定义一个Scope
*/
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface MyScope {
}
/**
* 注意是这个类上标注了自定义的一个主机@MyScope
*/
@MyScope
public class Laptop {
//构造上标注了@Inject
@Inject
public Laptop() {
Log.e("laptop","laptop");
}
}
/**
* 这里没有标注自定义的@MyScope
*/
public class Mobile {
//构造上标注了@Inject
@Inject
public Mobile() {
Log.e("mobile","mobile");
}
}
@MyScope //注意要在这里标注@MyScope,因为目标类ScopeActivity中,有个被@Inject标注的字段,而这个字段所属的类被@MyScope标注了,所以这个Component必须标注
@Component
public interface ScopeActivityComponent {
void inject(ScopeActivity activity);
}
public class ScopeActivity extends AppCompatActivity {
@Inject
Laptop laptop01;
@Inject
Laptop laptop02;
@Inject
Mobile mobile01;
@Inject
Mobile mobile02;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scope);
DaggerScopeActivityComponent.create().inject(this);
log(laptop01.hashCode()+"");
log(laptop02.hashCode()+"");
log(mobile01.hashCode()+"");
log(mobile02.hashCode()+"");
}
private void log(String msg){
Log.e("msg",msg);
}
}
结果如下:
com.zhourf.dagger.daggerexample E/laptop: laptop
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/msg: 186183467
com.zhourf.dagger.daggerexample E/msg: 186183467
com.zhourf.dagger.daggerexample E/msg: 146743176
com.zhourf.dagger.daggerexample E/msg: 2886945
可以看出:
被MyScope标注的Laptop类,构造方法只执行了一次,而laptop01和laptop02的地址值是同一个
没有被MyScope标注的Mobile类,构造方法执行了两次,mobile01和mobile02的地址值不同。
此外,刚才在上面描述时,有一句话,“在一定范围内能达到单例的效果”,那么这个范围是什么呢?
先看代码:---example12
/**
* Scope只能标注在注解上
* 这里自定义一个Scope
*/
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface MyScope {
}
/**
* 注意是这个类上标注了自定义的一个主机@MyScope
*/
@MyScope
public class Laptop {
//构造上标注了@Inject
@Inject
public Laptop() {
Log.e("laptop","laptop");
}
}
/**
* 这里没有标注自定义的@MyScope
*/
public class Mobile {
//构造上标注了@Inject
@Inject
public Mobile() {
Log.e("mobile","mobile");
}
}
@MyScope //注意要在这里标注@MyScope,因为目标类ScopeActivity中,有个被@Inject标注的字段,而这个字段所属的类被@MyScope标注了,所以这个Component必须标注
@Component
public interface ScopeActivityComponent {
void inject(ScopeActivity activity);
}
public class ScopeActivity extends AppCompatActivity {
@Inject
Laptop laptop01;
@Inject
Laptop laptop02;
@Inject
Mobile mobile01;
@Inject
Mobile mobile02;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scope);
DaggerScopeActivityComponent.create().inject(this);
log(laptop01.hashCode()+"");
log(laptop02.hashCode()+"");
log(mobile01.hashCode()+"");
log(mobile02.hashCode()+"");
startActivity(new Intent(this,Scope2Activity.class));
}
private void log(String msg){
Log.e("msg",msg);
}
}
@MyScope
@Component
public interface Scope2ActivityComponent {
void inject(Scope2Activity activity);
void inject(Scope3Activity activity);
}
public class Scope2Activity extends AppCompatActivity {
@Inject
Laptop laptop03;
@Inject
Laptop laptop04;
@Inject
Mobile mobile03;
@Inject
Mobile mobile04;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scope2);
DaggerScope2ActivityComponent.create().inject(this);
log(laptop03.hashCode()+"");
log(laptop04.hashCode()+"");
log(mobile03.hashCode()+"");
log(mobile04.hashCode()+"");
}
private void log(String msg){
Log.e("msg",msg);
}
}
public class Scope3Activity extends AppCompatActivity {
@Inject
Laptop laptop05;
@Inject
Laptop laptop06;
@Inject
Mobile mobile05;
@Inject
Mobile mobile06;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scope3);
DaggerScope2ActivityComponent.create().inject(this);
log(laptop05.hashCode()+"");
log(laptop06.hashCode()+"");
log(mobile05.hashCode()+"");
log(mobile06.hashCode()+"");
}
private void log(String msg){
Log.e("msg",msg);
}
}
结果如下:
com.zhourf.dagger.daggerexample E/laptop: laptop
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/msg: 186183467
com.zhourf.dagger.daggerexample E/msg: 186183467
com.zhourf.dagger.daggerexample E/msg: 146743176
com.zhourf.dagger.daggerexample E/msg: 2886945
com.zhourf.dagger.daggerexample E/laptop: laptop
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/msg: 106306550
com.zhourf.dagger.daggerexample E/msg: 106306550
com.zhourf.dagger.daggerexample E/msg: 91425783
com.zhourf.dagger.daggerexample E/msg: 128682596
com.zhourf.dagger.daggerexample E/laptop: laptop
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/msg: 76555776
com.zhourf.dagger.daggerexample E/msg: 76555776
com.zhourf.dagger.daggerexample E/msg: 16014905
com.zhourf.dagger.daggerexample E/msg: 98020478
在上面的的代码中,使用了ScopeActivityComponent 注入ScopeActivity,使用Scope2ActivityComponent,分别注入Scope2Activity和Scope3Activity,每个Activity中分别声明了Laptop和Mobile的两个字段。启动ScopeActivity后,会自动跳转到Scope2Activity,Scope2Activity自动跳转Scope3Activity
可以看出结果:
在ScopeActivity中:
com.zhourf.dagger.daggerexample E/laptop: laptop
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/msg: 186183467
com.zhourf.dagger.daggerexample E/msg: 186183467
com.zhourf.dagger.daggerexample E/msg: 146743176
com.zhourf.dagger.daggerexample E/msg: 2886945
Laptop构造执行了一次,两个laptop的地址相同
Mobile构造执行了两次,两个mobile的地址不同
在跳转到Scope2Activity后:
com.zhourf.dagger.daggerexample E/laptop: laptop
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/msg: 106306550
com.zhourf.dagger.daggerexample E/msg: 106306550
com.zhourf.dagger.daggerexample E/msg: 91425783
com.zhourf.dagger.daggerexample E/msg: 128682596
Laptop的构造重新执行了,且一次,两个laptop地址相同,又与ScopeActivity中的laptop地址不同
Mobile的构造重新执行了,两次,两个mobile地址不同,与ScopeActivity中的mobile地址不同。
在Scope3Activity中:
com.zhourf.dagger.daggerexample E/laptop: laptop
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/mobile: mobile
com.zhourf.dagger.daggerexample E/msg: 76555776
com.zhourf.dagger.daggerexample E/msg: 76555776
com.zhourf.dagger.daggerexample E/msg: 16014905
com.zhourf.dagger.daggerexample E/msg: 98020478
Laptop的构造重新执行了,且一次,两个laptop地址相同,又与ScopeActivity和Scope2Activity中的laptop地址不同
Mobile的构造重新执行了,两次,两个mobile地址不同,与ScopeActivity和Scope2Activity中的mobile地址不同。
结论:
1.@Scope是用于自定义注解的
2.@MyScope 必须同时标注在类上和对应的Component上。
3.被@MyScope标注后,在Component注入的同一个目标范围内,可以达到单例的表现效果,如果Component注入了多个目标,那么各自目标内,可以单例。但是多个目标不能共享单例。
Scope使用方式二
将自定义Scope标注在方法和Component上
步骤
1.使用@Scope自定义注解@TestScope
2.将@TestScope标注在module的provide方法上
3.将@TestScope标注在component上
4.使用Component进行注入实现。
示例代码如下,---example13
public class Green {
public Green() {
Log.e("green construct","green");
}
}
@Module
public class TestModule {
@TestScope //标注在provide方法上 只会取一次
@Provides
Green provideGreen(){
Log.e("green provide","green");
return new Green();
}
}
@TestScope
@Component(modules = TestModule.class)
public interface ColorActivityComponent {
void inject(ColorActivity activity);
}
public class ColorActivity extends AppCompatActivity {
@Inject
Green green1;
@Inject
Green green2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_color);
DaggerColorActivityComponent.create().inject(this);
log(green1.hashCode());
log(green2.hashCode());
}
private void log(int msg){
Log.e("color",msg+"");
}
}
运行结果:
com.zhourf.dagger.daggerexample E/green provide: green
com.zhourf.dagger.daggerexample E/green construct: green
com.zhourf.dagger.daggerexample E/color: 186183467
com.zhourf.dagger.daggerexample E/color: 186183467
Scope使用方式三
自定义注解,标注在类、component和provide上,混合使用。
示例代码 ,-----example13
//自定义一个Scope注解
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface TestScope {
}
public class Green {
public Green() {
Log.e("green construct","green");
}
}
public class Red {
public Red() {
Log.e("red construct","red");
}
}
public interface IBlue {
}
@TestScope
public class Blue implements IBlue {
@Inject
public Blue() {
Log.e("blue construct","blue");
}
}
public interface IOrange {
}
@TestScope
public class Orange implements IOrange {
@Inject
public Orange() {
Log.e("Orange construct","Orange");
}
}
@Module
public class TestModule {
@TestScope
@Provides
Green provideGreen(){
Log.e("green provide","green");
return new Green();
}
@Provides
Red provideRed(){
Log.e("red provide","red");
return new Red();
}
@Provides
IBlue provideBlue(Blue blue){
Log.e("blue provide","blue");
return blue;
}
@TestScope
@Provides
IOrange provideOrange(Orange orange)
{Log.e("orange provide","orange");
return orange;
}
}
@TestScope
@Component(modules = TestModule.class)
public interface ColorActivityComponent {
void inject(ColorActivity activity);
}
public class ColorActivity extends AppCompatActivity {
@Inject
Green green1;
@Inject
Green green2;
@Inject
Red red1;
@Inject
Red red2;
@Inject
IBlue blue1;
@Inject
IBlue blue2;
@Inject
IOrange orange1;
@Inject
IOrange orange2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_color);
DaggerColorActivityComponent.create().inject(this);
log("green1",green1.hashCode());
log("green2",green2.hashCode());
log("red1",red1.hashCode());
log("red2",red2.hashCode());
log("blue1",blue1.hashCode());
log("blue2",blue2.hashCode());
log("orange1",orange1.hashCode());
log("orange2",orange2.hashCode());
}
private void log(String tag,int msg){
Log.e(tag,msg+"");
}
}
结果如下:
com.zhourf.dagger.daggerexample E/green provide: green
com.zhourf.dagger.daggerexample E/green construct: green
com.zhourf.dagger.daggerexample E/red provide: red
com.zhourf.dagger.daggerexample E/red construct: red
com.zhourf.dagger.daggerexample E/red provide: red
com.zhourf.dagger.daggerexample E/red construct: red
com.zhourf.dagger.daggerexample E/blue construct: blue
com.zhourf.dagger.daggerexample E/blue provide: blue
com.zhourf.dagger.daggerexample E/blue provide: blue
com.zhourf.dagger.daggerexample E/Orange construct: Orange
com.zhourf.dagger.daggerexample E/orange provide: orange
com.zhourf.dagger.daggerexample E/green1: 186183467
com.zhourf.dagger.daggerexample E/green2: 186183467
com.zhourf.dagger.daggerexample E/red1: 146743176
com.zhourf.dagger.daggerexample E/red2: 2886945
com.zhourf.dagger.daggerexample E/blue1: 122148166
com.zhourf.dagger.daggerexample E/blue2: 122148166
com.zhourf.dagger.daggerexample E/orange1: 112546567
com.zhourf.dagger.daggerexample E/orange2: 112546567
结果分析
Green ,@TestScope标注在component和provide上,Green及构造上什么都不标注
com.zhourf.dagger.daggerexample E/green provide: green
com.zhourf.dagger.daggerexample E/green construct: green
com.zhourf.dagger.daggerexample E/green1: 186183467
com.zhourf.dagger.daggerexample E/green2: 186183467
调用了一次provide和一次构造,两个green的地址相同
Red,@TestScope只标注在component上,Red类及构造及provide上什么都不标注
com.zhourf.dagger.daggerexample E/red provide: red
com.zhourf.dagger.daggerexample E/red construct: red
com.zhourf.dagger.daggerexample E/red provide: red
com.zhourf.dagger.daggerexample E/red construct: red
com.zhourf.dagger.daggerexample E/red1: 146743176
com.zhourf.dagger.daggerexample E/red2: 2886945
调用了两次provide和两次构造,两个red对象地址不同,所以只标注在component上,没什么用
Blue,@TestScope标注在component及Blue类上,Blue构造标注@Inject,provide方法上什么都不标注
com.zhourf.dagger.daggerexample E/blue construct: blue
com.zhourf.dagger.daggerexample E/blue provide: blue
com.zhourf.dagger.daggerexample E/blue provide: blue
com.zhourf.dagger.daggerexample E/blue1: 122148166
com.zhourf.dagger.daggerexample E/blue2: 122148166
调用了两次provide和一次构造,两个blue对象地址相同,因为provide没有标注@TestScope,所以调用了两次,而类上标注了@TestScope,所以构造只执行了一次。
Orange,@TestScope同时标注在Component、provide和Orange类上
com.zhourf.dagger.daggerexample E/Orange construct: Orange
com.zhourf.dagger.daggerexample E/orange provide: orange
com.zhourf.dagger.daggerexample E/orange1: 112546567
com.zhourf.dagger.daggerexample E/orange2: 112546567
调用了一次构造和一次provide,两个oriange对象地址相同。provide优先级比类高,所以取到provide就一次了。
其实也就是说:
1.自定义Scope,单独标注类或provide上,都有“单例效果”。
2.自定义Scope,同时标注在类和provide上,provide优先级高。
3.component上必须标注Scope,才有效果。
然后再说@Singleton
@Scope
@Documented
@Retention(RUNTIME)
public @interface Singleton {}
这其实就是@Scope自定义注解的一种实现,和我们上面定义的@TestScope是一样的。
Lazy
一看这个词,就能想到懒加载,其含义也是类似的,在使用时再去加载。
1.在@Inject Lazy
2.在@Inject T t时,就直接取调用来源创建对象了
3.如果有两个@Inject Lazy
4.Lazy的get方法是获取T对象,当一个Lazy第一次get时,调用依赖来源创建对象,然后缓存,当第二次get时,获取的是缓存的对象,而不会再去调用依赖来源创建对象
5.两个Lazy不会共享缓存
示例代码 ----example14
public class HuaWei {
@Inject
public HuaWei() {
Log.e("huawei","huawei");
}
}
@Component
public interface HuaweiActivityComponent {
void inject(HuaweiActivity activity);
}
public class HuaweiActivity extends AppCompatActivity {
@Inject
HuaWei hw1;//这时就直接调用依赖来源去创建对象了
@Inject
Lazy lhw1;//此时没有调用依赖来源去创建对象
@Inject
Lazy lhw2;//此时没有调用依赖来源去创建对象
@Inject
HuaWei hw2;//这时就直接调用依赖来源去创建对象了
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_huawei);
DaggerHuaweiActivityComponent.create().inject(this);
Log.e("start","--------------------");
log("hw1",hw1.hashCode());
log("lhw1",lhw1.get().hashCode());//当第一次调用get时,才调用依赖来源去创建对象,然后缓存起来
log("lhw1",lhw1.get().hashCode());//当第二次调用get时,使用第一次的缓存
log("hw2",hw2.hashCode());
log("lhw2",lhw2.get().hashCode());//当第一次调用get时,才调用依赖来源去创建对象,然后缓存起来。需要注意的是两个Lazy是完全独立的,不会共享缓存
log("lhw2",lhw2.get().hashCode());//当第二次调用get时,使用第一次的缓存
}
private void log(String tag,int msg){
Log.e(tag,msg+"");
}
}
运行结果:
com.zhourf.dagger.daggerexample E/huawei: huawei //@Inject时就调用了构造
com.zhourf.dagger.daggerexample E/huawei: huawei //@Inject时就调用了构造
com.zhourf.dagger.daggerexample E/start: --------------------
com.zhourf.dagger.daggerexample E/hw1: 186183467
com.zhourf.dagger.daggerexample E/huawei: huawei //get时才去调用构造函数
com.zhourf.dagger.daggerexample E/lhw1: 146743176
com.zhourf.dagger.daggerexample E/lhw1: 146743176//第二次get就不调用构造了
com.zhourf.dagger.daggerexample E/hw2: 2886945
com.zhourf.dagger.daggerexample E/huawei: huawei //第二个Lazy的第一次get时,调用构造
com.zhourf.dagger.daggerexample E/lhw2: 122148166
com.zhourf.dagger.daggerexample E/lhw2: 122148166 //第二次get不调用构造
Provider
Provider ,字面意思 ,提供者。
1.使用@Inject Provider
2.当使用Provider.get()时才去调用构造函数,同时不会缓存对象
3.当使用第二次Provider.get(),会立即调用构造函数。
4.也就是说每次调用Provider.get()时都会调用构造函数,重新创建对象,就像一个T的工厂一样,源源不断生成,且每次都是new的 。
示例代码 example15
public class Table {
@Inject
public Table() {
Log.e("table construct","table");
}
}
@Component
public interface TableActivityComponent {
void inject(TableActivity activity);
}
public class TableActivity extends AppCompatActivity {
@Inject
Provider provider1;//此时没有调用构造函数
@Inject
Provider provider2;//此时没有调用构造函数
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_table);
DaggerTableActivityComponent.create().inject(this);
Log.e("tag","----------");
log("provider1 get1",provider1.get().hashCode());//此时调用构造函数,不缓存
log("provider1 get2",provider1.get().hashCode());//此时依然调用构造函数,重新创建
log("provider2 get1",provider2.get().hashCode());//此时调用构造函数,不缓存
log("provider2 get2",provider2.get().hashCode());//此时依然调用构造函数,重新创建
}
private void log(String tag,int msg){
Log.e(tag,msg+"");
}
}
运行结果:
com.zhourf.dagger.daggerexample E/tag: ----------
com.zhourf.dagger.daggerexample E/table construct: table
com.zhourf.dagger.daggerexample E/provider1 get1: 186183467
com.zhourf.dagger.daggerexample E/table construct: table
com.zhourf.dagger.daggerexample E/provider1 get2: 146743176
com.zhourf.dagger.daggerexample E/table construct: table
com.zhourf.dagger.daggerexample E/provider2 get1: 2886945
com.zhourf.dagger.daggerexample E/table construct: table
com.zhourf.dagger.daggerexample E/provider2 get2: 122148166
Set
@IntoSet 将一个值add入set
1.标注在provide方法上,可以将provide方法的返回值add到Set中。
2.使用@Inject Set set 字段 ,可以从provide方法取得依赖。
3.相同返回值的多个provide方法,最终都会将值存到同一个Set内。
4.都使用@IntoSet标注,且返回值不同的provide方法,会将值存到各自的Set Set中。
5.一个component,inject多个目标类时,共享这个Set。
@ElementsIntoSet 将多个值add入set
1.与@IntoSet功能类似,也是往Set中add值。
2.@IntoSet是一个一个值的add,@ElementsIntoSet则是一次可以add多个。
3.也是标注在provide方法上,但是其返回值是Set类型。
注意:
对于二者,同一个component内,不论module多少,Set共享,就是同一个T的,用的都是同一个Set。
不同的component之间,Set独立不共享。
实例代码 ----example16
public class Desk {
public String name;
public Desk(String name) {
this.name = name;
}
@Override
public String toString() {
return "Desk{" +
"name='" + name + '\'' +
'}';
}
}
public class Chair {
public String name;
@Override
public String toString() {
return "Chair{" +
"name='" + name + '\'' +
'}';
}
public Chair(String name) {
this.name = name;
}
}
@Module
public class DeskModule {
@Provides
@IntoSet //这里的Desk会被放到Set中 对应的返回值其实是Set
Desk provideDesk(){
return new Desk(" DeskModule intoset dest1");
}
@Provides
@IntoSet //这里的Desk会被放到Set中,且是同一个set,就算跨Activity了也是同一个 对应的返回值其实是Set
Desk provideDesk3(){
return new Desk("DeskModule intoset dest2");
}
@Provides
@IntoSet //这里的Chair会被放到Set中 对应的返回值其实是Set
Chair provideChair(){
return new Chair("DeskModule intoset chair1");
}
@Provides
@ElementsIntoSet //这里的Chair会被放到Set中 且是同一个Set 对应的返回值其实是Set
Set provideSetChair(){
Set set = new HashSet<>();
set.add(new Chair(" DeskModule elementsIntoSet chair2"));
set.add(new Chair("DeskModule elementsIntoSet chair3"));
return set;
}
@Provides //返回值是Desk
Desk provideDesk2(){
return new Desk("DeskModule desk3");
}
@Provides
@IntoSet //这里的Chair会被放到Set中 且是同一个Set 对应的返回值其实是Set
String provideName(){
return "DeskModule aaaa";
}
}
@Module
public class Desk2Module {
@Provides
@IntoSet //这个返回值是Set 也会被放到Set中 且与DeskModule中的是同一个Set
Desk provideDesk(){
return new Desk("Desk2Module intoset 2dest4");
}
@Provides
@IntoSet //这个返回值是Set 也会被放到Set中 且与DeskModule中的是同一个Set
Chair provideChair(){
return new Chair("Desk2Module intoset 2chair4");
}
@Provides
@ElementsIntoSet //这个返回值是Set 也会被放到Set中 且与DeskModule中的是同一个Set
Set provideSetChair(){
Set set = new HashSet<>();
set.add(new Chair("Desk2Module ElementsIntoSet 2chair5"));
set.add(new Chair("Desk2Module ElementsIntoSet 2hair6"));
return set;
}
@Provides
@IntoSet//这个返回值是Set 也会被放到Set中 且与DeskModule中的是同一个Set
String provideName(){
return "Desk2Module 2bbbb";
}
}
@Component(modules = {DeskModule.class,Desk2Module.class})
public interface SetActivityComponent {
void inject(SetActivity activity);
void inject(DeskActivity activity);
}
public class SetActivity extends AppCompatActivity {
@Inject
Set ss;
@Inject
Set sd;
@Inject
Set sc;
@Inject
Desk d;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_set);
DaggerSetActivityComponent.create().inject(this);
Log.e("start","---------");
for(String str:ss){
Log.e("ss=",str);
}
for(Desk d :sd){
Log.e("sd=",d.toString());
}
for(Chair c : sc)
{
Log.e("sc=",c.toString());
}
Log.e("d=",d.toString());
startActivity(new Intent(this,DeskActivity.class));
}
}
public class DeskActivity extends AppCompatActivity {
@Inject
Set ss;
@Inject
Set sd;
@Inject
Set sc;
@Inject
Desk d;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_desk);
DaggerSetActivityComponent.create().inject(this);
Log.e("start","deskActivity---------");
for(String str:ss){
Log.e("ss=",str);
}
for(Desk d :sd){
Log.e("sd=",d.toString());
}
for(Chair c : sc)
{
Log.e("sc=",c.toString());
}
Log.e("d=",d.toString());
//startActivity(new Intent(this,ChairActivity.class));
}
}
代码说明:
DeskModule内,使用@IntoSet @ElementsIntoSet 返回了Set Set Set ,示例值都是以DeskModule开头
Desk2Module内,使用@IntoSet @ElementsIntoSet 返回了Set Set Set ,示例值都是以Desk2Module开头
SetActivityComponent中,module={DeskModule,Desk2Module}
且inject(SetActivity) 和 inject(DeskActivity)
SetActivity 和DeskActivity 中分别对Set Set Set 进行访问
结果显示是两个module中的Desk Chair String 都add到了同一个Set Set Set 中了,说明同一个component多个module是共用一个Set的
运行结果:
SetActivity内log的结果:
com.zhourf.dagger.daggerexample E/start: ---------
com.zhourf.dagger.daggerexample E/ss=: DeskModule aaaa
com.zhourf.dagger.daggerexample E/ss=: Desk2Module 2bbbb
com.zhourf.dagger.daggerexample E/sd=: Desk{name=' DeskModule intoset dest1'}
com.zhourf.dagger.daggerexample E/sd=: Desk{name='DeskModule intoset dest2'}
com.zhourf.dagger.daggerexample E/sd=: Desk{name='Desk2Module intoset 2dest4'}
com.zhourf.dagger.daggerexample E/sc=: Chair{name='Desk2Module ElementsIntoSet 2hair6'}
com.zhourf.dagger.daggerexample E/sc=: Chair{name='DeskModule intoset chair1'}
com.zhourf.dagger.daggerexample E/sc=: Chair{name='Desk2Module ElementsIntoSet 2chair5'}
com.zhourf.dagger.daggerexample E/sc=: Chair{name='Desk2Module intoset 2chair4'}
com.zhourf.dagger.daggerexample E/sc=: Chair{name='DeskModule elementsIntoSet chair3'}
com.zhourf.dagger.daggerexample E/sc=: Chair{name=' DeskModule elementsIntoSet chair2'}
com.zhourf.dagger.daggerexample E/d=: Desk{name='DeskModule desk3'}
DeskActivity内log的结果,与上面是一样的。
com.zhourf.dagger.daggerexample E/start: deskActivity---------
com.zhourf.dagger.daggerexample E/ss=: DeskModule aaaa
com.zhourf.dagger.daggerexample E/ss=: Desk2Module 2bbbb
com.zhourf.dagger.daggerexample E/sd=: Desk{name='Desk2Module intoset 2dest4'}
com.zhourf.dagger.daggerexample E/sd=: Desk{name=' DeskModule intoset dest1'}
com.zhourf.dagger.daggerexample E/sd=: Desk{name='DeskModule intoset dest2'}
com.zhourf.dagger.daggerexample E/sc=: Chair{name='DeskModule elementsIntoSet chair3'}
com.zhourf.dagger.daggerexample E/sc=: Chair{name=' DeskModule elementsIntoSet chair2'}
com.zhourf.dagger.daggerexample E/sc=: Chair{name='Desk2Module ElementsIntoSet 2chair5'}
com.zhourf.dagger.daggerexample E/sc=: Chair{name='Desk2Module intoset 2chair4'}
com.zhourf.dagger.daggerexample E/sc=: Chair{name='DeskModule intoset chair1'}
com.zhourf.dagger.daggerexample E/sc=: Chair{name='Desk2Module ElementsIntoSet 2hair6'}
com.zhourf.dagger.daggerexample E/d=: Desk{name='DeskModule desk3'}
在上面的代码基础上,增加一个ChairActivityComponent-ChairModule-ChairActivity
如下代码:
@Module
public class ChairModule {
@Provides
@IntoSet
Desk provideDesk3(){
return new Desk("ChairModule desk---");
}
@Provides
@ElementsIntoSet
Set provideDesks(){
Set s = new HashSet<>();
s.add(new Desk("ChairModule ElementsIntoSet desk///"));
s.add(new Desk("ChairModule ElementsIntoSet desk+++"));
return s;
}
}
@Component(modules = ChairModule.class)
public interface ChairActivityComponent {
void inject(ChairActivity activity);
}
public class ChairActivity extends AppCompatActivity {
// @Inject
// Set ss;
@Inject
Set sd;
// @Inject
// Set sc;
//
// @Inject
// Desk d;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chair);
DaggerChairActivityComponent.create().inject(this);
Log.e("start","ChairActivity---------");
// for(String str:ss){
// Log.e("ss=",str);
// }
for(Desk d :sd){
Log.e("sd=",d.toString());
}
// for(Chair c : sc)
// {
// Log.e("sc=",c.toString());
// }
// Log.e("d=",d.toString());
}
}
运行结果如下
com.zhourf.dagger.daggerexample E/start: ChairActivity---------
com.zhourf.dagger.daggerexample E/sd=: Desk{name='ChairModule ElementsIntoSet desk+++'}
com.zhourf.dagger.daggerexample E/sd=: Desk{name='ChairModule desk---'}
com.zhourf.dagger.daggerexample E/sd=: Desk{name='ChairModule ElementsIntoSet desk///'}
ChairActivityComponent与SetActivityComponent是独立的,在ChairModule只是增加了Set,在ChairActivity中只能访问Set 且值只是ChairModule中增加的。说明了 两个component之间Set是独立的,互不影响。
IntoMap
@IntoSet是将同一个T的值存到一个Set中,看@IntoMap,应该也明白是将值存到一个Map中,只是增加了key。key的表示也是用注解的形式,如@StringKey @ClassKey
示例代码如下 example17
public class Mouse {
public String name;
@Override
public String toString() {
return "Mouse{" +
"name='" + name + '\'' +
'}';
}
public Mouse(String name) {
this.name = name;
}
}
@Module
public class MouseModule {
@Provides
@IntoMap
@StringKey("key01")
Mouse provideMouse(){ //注意这里的返回值是T
return new Mouse("mouse01");
}
@Provides
@IntoMap
@StringKey("key02")
Mouse provideMouse2(){
return new Mouse("mouse02");
}
}
@Component(modules = MouseModule.class)
public interface MapActivityComponent {
void inject(MapActivity activity);
}
public class MapActivity extends AppCompatActivity {
@Inject //这里用这种方式注入结果
Map map;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
DaggerMapActivityComponent.create().inject(this);
for(Map.Entry entry : map.entrySet()){
Log.e(entry.getKey(),entry.getValue().toString());
}
}
}
运行结果:
com.zhourf.dagger.daggerexample E/key01: Mouse{name='mouse01'}
com.zhourf.dagger.daggerexample E/key02: Mouse{name='mouse02'}
结果显示,module中的两个provide方法都将值into中了map,key也是各自定义的。
扩展:::
1.一个component,多个module,则Map共用吗?
2.provideMouse方法 能放到Map中吗?
示例代码, example17
public class Mouse {
public String name;
@Override
public String toString() {
return "Mouse{" +
"name='" + name + '\'' +
'}';
}
public Mouse(String name) {
this.name = name;
}
}
public class KeyBoard {
public String name;
@Override
public String toString() {
return "KeyBoard{" +
"name='" + name + '\'' +
'}';
}
public KeyBoard(String name) {
this.name = name;
}
}
@Module
public class MouseModule {
@Provides
@IntoMap
@StringKey("key01")
Mouse provideMouse(){
return new Mouse("mouse01");
}
@Provides
@IntoMap
@StringKey("key02")
Mouse provideMouse2(){
return new Mouse("mouse02");
}
}
@Module
public class Mouse2Module {
@Provides
@IntoMap
@StringKey("key03")
Mouse provideMouse3(){
return new Mouse("mouse03");
}
@Provides
@IntoMap
@ClassKey(Mouse.class)
Mouse provideMouse4(){
return new Mouse("mouse04");
}
@Provides
@IntoMap
@ClassKey(MouseModule.class)
KeyBoard provideMouse5(){
return new KeyBoard("keyboard01");
}
@Provides
@IntoMap
@ClassKey(Mouse2Module.class)
Object provideMouse6(){
return new KeyBoard("object");
}
}
@Component(modules = {MouseModule.class,Mouse2Module.class})
public interface MapActivityComponent {
void inject(MapActivity activity);
}
public class MapActivity extends AppCompatActivity {
@Inject
Map map;
@Inject
Map,Mouse > map2;
@Inject
Map,KeyBoard> map3;
@Inject
Map,Object> map4;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
DaggerMapActivityComponent.create().inject(this);
Log.e("tag","-----------");
for(Map.Entry entry : map.entrySet()){
Log.e(entry.getKey(),entry.getValue().toString());
}
Log.e("tag","-----------");
for(Map.Entry,Mouse> entry : map2.entrySet()){
Log.e(entry.getKey().getName(),entry.getValue().toString());
}
Log.e("tag","-----------");
for(Map.Entry,KeyBoard> entry : map3.entrySet()){
Log.e(entry.getKey().getName(),entry.getValue().toString());
}
Log.e("tag","-----------");
for(Map.Entry,Object> entry : map4.entrySet()){
Log.e(entry.getKey().getName(),entry.getValue().toString());
}
}
}
运行结果:
com.zhourf.dagger.daggerexample E/tag: -----------
com.zhourf.dagger.daggerexample E/key01: Mouse{name='mouse01'}
com.zhourf.dagger.daggerexample E/key02: Mouse{name='mouse02'}
com.zhourf.dagger.daggerexample E/key03: Mouse{name='mouse03'}
com.zhourf.dagger.daggerexample E/tag: -----------
com.zhourf.dagger.daggerexample E/com.zhourf.dagger.daggerexample.example17.Mouse: Mouse{name='mouse04'}
com.zhourf.dagger.daggerexample E/tag: -----------
com.zhourf.dagger.daggerexample E/com.zhourf.dagger.daggerexample.example17.MouseModule: KeyBoard{name='keyboard01'}
com.zhourf.dagger.daggerexample E/tag: -----------
com.zhourf.dagger.daggerexample E/com.zhourf.dagger.daggerexample.example17.Mouse2Module: KeyBoard{name='object'}
结论:
1.在同一个component内,无论几个module,都共用同一个类型的Map
2.Map的key与value的类型严格对应,这里不适用“接口的引用指向子类的对象”这句话。
再次扩展:如果是两个component,注入到两个类中呢?-example18
@Module
public class Map1Module {
@Provides
@IntoMap
@StringKey("key01")
String provideStr1(){
return "value01";
}
}
@Component(modules = {Map1Module.class})
public interface Map1ActivityComponent {
void inject(Map1Activity activity);
}
public class Map1Activity extends AppCompatActivity {
@Inject
Map map;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map1);
DaggerMap1ActivityComponent.create().inject(this);
Log.e("tag","Map1Activity-----------1111");
for(Map.Entry entry:map.entrySet())
{
Log.e(entry.getKey(),entry.getValue());
}
startActivity(new Intent(this,Map2Activity.class));
}
}
@Module
public class Map2Module {
@Provides
@IntoMap
@StringKey("key02")
String provideStr1(){
return "value02";
}
}
@Component(modules = {Map2Module.class})
public interface Map2ActivityComponent {
void inject(Map2Activity activity);
}
public class Map2Activity extends AppCompatActivity {
@Inject
Map map;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map2);
DaggerMap2ActivityComponent.create().inject(this);
Log.e("tag","Map2Activity-----------222");
for(Map.Entry entry:map.entrySet())
{
Log.e(entry.getKey(),entry.getValue());
}
}
}
运行结果:
com.zhourf.dagger.daggerexample E/tag: Map1Activity-----------1111
com.zhourf.dagger.daggerexample E/key01: value01
com.zhourf.dagger.daggerexample E/tag: Map2Activity-----------222
com.zhourf.dagger.daggerexample E/key02: value02
可以看到两个component的情况下,Map是各自独立的。
扩展:如何自定义Map的key?
在注释类型中声明的方法的返回类型,必须符合下列类型:
1.基本数据类型
2.String
3.Class
4.枚举类型
5.注解类型
6.以上数据类型的数组
看一个示例,example19
//自定义个枚举
public enum TestEnum {
A,B,C,D
}
//自定义Map的key,方法返回值是枚举
@MapKey
public @interface CustKey {
TestEnum value();
}
@Module
public class TestModule {
@Provides
@IntoMap
@CustKey(TestEnum.A)
String provideStrA(){
return "aaa";
}
@Provides
@IntoMap
@CustKey(TestEnum.B)
String provideStrB(){
return "bbb";
}
}
@Component(modules = TestModule.class)
public interface KeyActivityComponent {
void inject(KeyActivity activity);
}
public class KeyActivity extends AppCompatActivity {
@Inject
Map map;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_key);
DaggerKeyActivityComponent.create().inject(this);
for(Map.Entry entry:map.entrySet())
{
Log.e(entry.getKey().toString(),entry.getValue());
}
}
}
运行结果:
com.zhourf.dagger.daggerexample E/A: aaa
com.zhourf.dagger.daggerexample E/B: bbb
@Component的dependencies
试想下:
Component1提供了 A B C的依赖
Component2提供了 D E F的依赖
那么在一个目标类内@Inject A a;@Inject D d了,那么怎么实现?
其实就是,每个component都有各自的提供依赖功能,怎么使用的问题。
大家都知道Component(modules = {}) 中module的作用,其实还有个dependencies,也是类似的功能,区别在于 :modules=Module类,dependencies=其他的Component ,这样就把其他component的功能引入到自身了。
看下实例 example21
public class Table {
@Inject
public Table() {
}
public void name(){
Log.e("Table tag","Table");
}
}
@Module
public class TableModule {
@Provides
Table provideTable(){
return new Table();
}
}
@Component(modules = TableModule.class)
public interface TableComponent {
//这么定义,会从所依赖的module中寻找
//一般是供其他component依赖时这么定义
Table getTable();
}
public class Cup {
@Inject
public Cup() {
}
public void name(){
Log.e("cup tag","cups");
}
}
@Module
public class CupModule {
@Provides
Cup provideCup(){
return new Cup();
}
}
//注意这里的dependencies
@Component(modules = CupModule.class,dependencies = TableComponent.class)
public interface CupActivityComponent {
void inject(CupActivity activity);
}
public class CupActivity extends AppCompatActivity {
@Inject
Cup cup;
@Inject
Table table;//在TableComponent 中可以找到依赖来源
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cup);
DaggerCupActivityComponent
.builder()
.tableComponent(DaggerTableComponent.create())//因为CupActivityComponent dependencies了TableComponent,所以这里需要传入TableComponent的实例
.build()
.inject(this);
cup.name();
table.name();
}
}
运行结果:
com.zhourf.dagger.daggerexample E/cup tag: cups
com.zhourf.dagger.daggerexample E/Table tag: Table
@Subcomponent
看名字,就猜个大概,Component 的 sub ,sub 子的意思。
这其实也是Component的一种依赖方式。
更确切的说,subcomponent 继承了Component的依赖,并拥有自己的依赖。
比如:
Component1 可以提供A B C 依赖
Subcomponent1 可以提供 D E 依赖
SubComponent2 可以提供 F依赖
那么:Subcomponent1 的inject的目标类中,可以提供ABCDE依赖
SubComponent2的inject的目标类中,可以提供ABCF依赖
注意:字的Component上必须标注为@Subcomponent
看示例代码 example22
提供全局的Application的Component
首先自定义DaggerApplication,并在AndroidManifest中做修改
public class DaggerApplication extends Application {
private static DaggerApplication instance;
@Override
public void onCreate() {
super.onCreate();
instance = this;
}
public static DaggerApplication getInstance(){
return instance;
}
}
提供Application的Module
@Module
public class ApplicationModule {
@Provides
DaggerApplication provideApplication(){
return DaggerApplication.getInstance();
}
}
定义类Lion 及其module component
public class Lion {
public Lion() {
}
public void roar(){
Log.e("lion","lion");
}
}
@Module
public class LionModule {
@Provides
Lion provideLion()
{
return new Lion();
}
}
//注意这里是Subcomponent
@Subcomponent(modules = LionModule.class)
public interface LionComponent {
void inject(AnimalActivity activity);
}
定义类Tiger 及其module component
public class Tiger {
public Tiger() {
}
public void roar()
{
Log.e("roar","tiger");
}
}
@Module
public class TigerModule {
@Provides
Tiger provideTiger()
{
return new Tiger();
}
}
//注意这里是sub
@Subcomponent(modules = TigerModule.class)
public interface TigerComponent {
void inject(TigerActivity activity);
}
定义基Component,并将Lion和TigerComponent置为此的sub
@Component(modules = ApplicationModule.class)
public interface AnimalActivityComponent {
LionComponent plus();
TigerComponent plus2();
}
看一个Activity
public class AnimalActivity extends AppCompatActivity {
@Inject
Lion lion;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_animal3);
DaggerAnimalActivityComponent.builder().build()//获取基Component
.getLion()//获取子component LionComponent
.inject(this); //注入此地
lion.roar();
startActivity(new Intent(this,TigerActivity.class));
}
}
public class TigerActivity extends AppCompatActivity {
//自身提供的依赖
@Inject
Tiger tiger;
//获取了基Component提供的依赖,这样就获取到了全局的一个application
@Inject
DaggerApplication application;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tiger);
AnimalActivityComponent component = DaggerAnimalActivityComponent.builder().build();
Log.e("tag", "TigerActivity......");
component.getTiger().inject(this);
tiger.roar();
Log.e("tag", "applicaion=" + application.getPackageName());
}
}
运行结果:
com.zhourf.dagger.daggerexample E/lion: lion
com.zhourf.dagger.daggerexample E/tag: TigerActivity......
com.zhourf.dagger.daggerexample E/roar: tiger
com.zhourf.dagger.daggerexample E/tag: applicaion=com.zhourf.dagger.daggerexample
你可能感兴趣的:(Dagger2)