浅入浅出Dagger2|浅入浅出Dagger2 — 基本使用与理解篇

什么是Dagger2 ?

Dagger is a fully static, compile-time dependency injection framework for
both Java and Android. It is an adaptation of an earlier version
created bySquare and now maintained by Google.
Dagger aims to address many of the development and performance issues that have
plagued reflection-based solutions.
dagger2是一个基于JSR-330标准的依赖注入框架,在编译期间自动生成代码,负责依赖对象的创建。butterknife也是一个依赖注入框架。不过butterknife黄油刀,Dagger2叫做利器,他的主要作用,就是对象的管理,其目的是为了降低程序耦合。
浅入浅出Dagger2|浅入浅出Dagger2 — 基本使用与理解篇
文章图片
依赖注入 Java 依赖注入标准 JSR-330 简介概念
JSR-330 是 Java 的依赖注入标准。定义了如下的术语描述依赖注入:
  • A 类型依赖 B类型(或者说 B 被 A 依赖),则 A类型 称为”依赖(物) dependency”
  • 运行时查找依赖的过程,称为”解析 resolving“依赖
  • 如果找不到依赖的实例,称该依赖是”不能满足的 unsatisfied”
  • 在”依赖注入 dependency injection”机制中,提供依赖的工具称为”依赖注入器 dependency injector”
依赖注入
我们知道Dagger是一个依赖注入的框架,那么什么是依赖注入呢?
我们在activity中有可能会用到很多很多的类,这些类要在activity中进行实例化,这样就导致我们的activity非常依赖这么多的类,这样的程序耦合非常
严重,不便于维护和扩展,有什么办法可以不去依赖这些类呢,这时候就需要有一个容器(IoC),将这些类放到这个容器里并实例化,我们activity在用
到的时候去容器里面取就可以了,我们从依赖类到依赖这个容器,实现了解耦,这就是我所理解的依赖注入,即所谓控制反转;
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫依赖查找(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
浅入浅出Dagger2|浅入浅出Dagger2 — 基本使用与理解篇
文章图片
举个栗子 提示:本篇文章内容代码改动次数较多,所以为了保留原代码,分次上传只需进入源码地址clone下来,并进入不同的commit即可查看相关正确代码。
浅入浅出Dagger2|浅入浅出Dagger2 — 基本使用与理解篇
文章图片
20181229160200.png Dagger接入项目 简单的说 Dagger就是用来创造这个容器,所有需要被依赖的对象在Dagger的容器中实例化,并通过Dagger注入到合适的地方,实现解耦,MVP框架就是为解耦而生,因此MVP和Dagger是绝配;
从简单示例入门 (1) app.gradle引入依赖库
dependencies { implementation 'com.google.dagger:dagger:2.20' annotationProcessor 'com.google.dagger:dagger-compiler:2.20' }

(2)总结几个很重要的“单词”
@Inject
通常在需要依赖的地方使用这个注解。换句话说,你用它告诉Dagger这个类或者字段需要依赖注入。这样,Dagger就会构造一个这个类的实例并满足他们的依赖。 官方点说就是带有此注解的属性或构造方法将参与到依赖注入中,Dagger2会实例化有此注解的类。
@Module
Modules类里面的方法专门用来提供依赖,他就像一个工厂一样去生产需要添加依赖的实例。所以我们定义一个类,用@Module来注解,这样Dagger在构造类的实例的时候,就知道从哪里去找到需要的依赖。modules的一个重要特性是它们设计为分区并组合在一起(例如,我们的app中可以有多个组成在一起的modules)。它里面定义一些用@Provides注解的以provide开头的方法,这些方法就是所提供的依赖,Dagger2会在该类中寻找实例化某个类所需要的依赖。
@Provides
上面引入了这个概念了。在modules中,我们定义的方法是用@Provides这个注解,以此来告诉Dagger我们想要构造对象并提供这些依赖。
@Component
Components从根本上来说他就是一个注入器,也可以说是用来将@Inject和@Module联系起来的桥梁,它的主要作用就是连接这两个部分。Components可以提供所有定义了的类型的实例(inject需要),比如:我们必须用@Component注解一个接口然后列出所有的 。功能是从@Module中获取依赖并将依赖注入给@Inject
(3)实战操练
public class Rose { public String whisper() { return "My lover"; } }

public class Pot { private Rose mRose; public Pot(Rose mRose) { this.mRose = mRose; }public String show() { return mRose.whisper(); } }

public class DaggerActivity extends AppCompatActivity {@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_dagger); toastWhisper(); }private void toastWhisper() { Rose rose = new Rose(); Pot pot = new Pot(rose); Toast.makeText(this, pot.show(), Toast.LENGTH_SHORT).show(); } }

使用Dagger2进行依赖注入如下:
public class Rose { @Inject public Rose() { }public String whisper() { return "My lover"; } } public class Pot { private Rose mRose; @Inject public Pot(Rose mRose) { this.mRose = mRose; }public String show() { return mRose.whisper(); } } public class DaggerActivity extends AppCompatActivity { @Inject Pot pot; // injected field can not be private@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_dagger); // 这个类是重新编译后Dagger2自动生成的,所以写这行代码之前要先编译一次 Build --> Rebuild Project DaggerDaggerActivityComp.create().inject(this); toastWhisper(); }private void toastWhisper() { Toast.makeText(this, pot.show(), Toast.LENGTH_SHORT).show(); } }

这样我们就可以让目标类DaggerActivity中所依赖的其他类,与其他类的构造函数之间有了一种无形的映射联系。 这个时候Dagger2就会去找这个类的实例,文章开头也说了Components是一个桥梁,Dagger2会到中介Components中去找这个实例的(其实是借助Compoent找,他类似中介)。
所以要创建一个Component,概念也说了:我们必须用@Component注解一个接口然后列出所有的 ,他提供的是一系列的接口。
浅入浅出Dagger2|浅入浅出Dagger2 — 基本使用与理解篇
文章图片
DaggerDaggerActivityComp生成位置 现在了解下@Inject@Component两个API,想要使用Dagger2进行依赖注入,至少要使用到这两个注解。
@Inject用于标记需要注入的依赖,或者标记用于提供依赖的方法。
@Component则可以理解为注入器,在注入依赖的目标类MainActivity使用Component完成注入。
@Inject
依赖注入中第一个并且是最重要的就是@Inject注解,标记那些应该被依赖注入框架提供的依赖。在Dagger 2中有3种不同的方式来提供依赖:
  1. 构造器注入,@Inject标注在构造器上其实有两层意思。
    ①告诉Dagger2可以使用这个构造器构建对象。如Rose
    ②注入构造器所需要的参数的依赖。 如Pot类,构造上的Rose会被注入。
    构造器注入的局限:如果有多个构造器,我们只能标注其中一个,无法标注多个。
  2. 属性注入
    DaggerActivity类,标注在属性上。被标注的属性不能使用private修饰,否则无法注入。
    属性注入也是Dagger2中使用最多的一个注入方式。
  3. 方法注入
标注在public方法上,Dagger2会在构造器执行之后立即调用这个方法。
方法注入和属性注入基本上没有区别, 那么什么时候应该使用方法注入呢?
比如该依赖需要this对象的时候,使用方法注入可以提供安全的this对象,因为方法注入是在构造器之后执行的。
/** * Method injection is used here to safely reference {@code this} after the object is created. * For more information, see Java Concurrency in Practice. */ @Inject void setupListeners() { mTasksView.setPresenter(this); }

@Component
@Inject注解只是JSR-330中定义的注解,这个注解本身并没有作用,它需要依赖于注入框架才具有意义,用来标记需要被注入框架注入的方法,属性,构造。
而Dagger2则是用Component来完成依赖注入的,可以理解为注入器,@Component可以说是Dagger2中最重要的一个注解。
@Component public interface DaggerActivityComp { void inject(DaggerActivity daggerActivity); }

命名方式推荐为:目标类名+Component,在编译后Dagger2就会为我们生成DaggerXXXComponent这个类,它是我们定义的xxxComponent的实现,在目标类中使用它就可以实现依赖注入了。
Component中一般使用两种方式定义方法。
  1. void inject(目标类 obj); Dagger2会从目标类开始查找@Inject注解,自动生成依赖注入的代码,调用inject可完成依赖的注入。
  2. Object getObj(); 如:Pot getPot();
    Dagger2会到Pot类中找被@Inject注解标注的构造器,自动生成提供Pot依赖的代码,这种方式一般为其他Component提供依赖。(一个Component可以依赖另一个Component)
Dagger2框架以Component中定义的方法作为入口,到目标类中寻找@Inject标注,生成一系列提供依赖的Factory类和注入依赖的Injector类。
而Component则是联系Factory和Injector,最终完成依赖的注入。
@Module和@Provides
使用@Inject标记构造器提供依赖是有局限性的,比如说我们需要注入的对象是第三方库提供的,我们无法在第三方库的构造器上加上@Inject注解。
或者,我们使用依赖倒置的时候,因为需要注入的对象是抽象的,@Inject也无法使用,因为抽象的类并不能实例化,比如我们这里使用如下两个类OkHttpClient和RetrofitManager设定不可改动代码的情况:
public class OkHttpClient { private int timeout; public OkHttpClient() { }public int getTimeout() { return timeout; }public void setTimeout(int timeout) { this.timeout = timeout; } }@Module public class DaggeActivityModule { @Provides OkHttpClient provideOkHttpClient() { return new OkHttpClient(); } }

private void toastWhisper() { Toast.makeText(this, pot.show(), Toast.LENGTH_SHORT).show(); Toast.makeText(this, okHttpClient.toString(), Toast.LENGTH_SHORT).show(); }

编写步骤: 第一步,编写Module类并使用@Module标注这个类,编写方法返回值为我们需要inject的类型并使用@Provides标注这个方法;
第二步,编写Component接口,使用@Component标注这个接口,并使用modules=的方法链接上第一步中编写的Module类;
之后的步骤就和 1 中的inject一样了。
@Module需要和@Provide是需要一起使用的时候才具有作用的,并且@Component也需要指定了该Module的时候。
@Module是告诉Component,可以从这里获取依赖对象。Component就会去找被@Provide标注的方法,相当于构造器的@Inject,可以提供依赖。
还有一点要说的是,@Component可以指定多个@Module的,如果需要提供多个依赖的话。并且Component也可以依赖其它Component存在。
复杂Module使用:
1、如果我们希望在使用的时候才传入一些配置,直接使用Module的构造参数传入即可,这种用法注意DaggerActivity中Component实例化的时候使用builder模式传入了我们需要传入的值;
@Module public class DaggeActivityModule { private int timeout; public DaggeActivityModule(int timeout) { this.timeout = timeout; }@Provides OkHttpClient provideOkHttpClient() { OkHttpClient client = new OkHttpClient(); client.setTimeout(timeout); return client; }@Provides RetrofitManager provideretrofitManager(OkHttpClient client) { return new RetrofitManager(client); } }

public class DaggerActivity extends AppCompatActivity { private static final String TAG = "DaggerActivity"; @Inject Pot pot; @Inject Rose rose; @Inject Flower flower; @Inject OkHttpClient okHttpClient; @Inject RetrofitManager retrofitManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_dagger); // 这个类是重新编译后Dagger2自动生成的,所以写这行代码之前要先编译一次 Build --> Rebuild Project DaggerDaggerActivityComp.builder().daggeActivityModule(new DaggeActivityModule(3000)).flowerModule(new FlowerModule()).build().inject(this); toastWhisper(); }private void toastWhisper() { Log.d(TAG, " pot.show() is :" + pot.show()); Log.d(TAG, " rose is :" + rose.whisper()); Log.d(TAG, " flower is :" + flower.toString()); Log.d(TAG, " okHttpClient.toString() is :" + okHttpClient.toString()); Log.d(TAG, " retrofitManager.getOkHttpClient().toString() is :" + retrofitManager.getOkHttpClient().toString()); }}

可以看到,被@Module注解的类生成的也是Factory。
浅入浅出Dagger2|浅入浅出Dagger2 — 基本使用与理解篇
文章图片
20181228151432.png
a、在Module的构造函数带有参数且参数被使用的情况下,所生产的Component类就没有create()方法了。
b、熟练使用1和2,我们就能配合mvp进行使用dagger2了,比如将presenter注入到view层;值得一提的是谷歌不推荐直接将presenter的构造参数添加注解,更加推荐的是将presenter放到Module里进行管理,因为这样代码更加容易管理。
@Module需要和@Provide是需要一起使用的时候才具有作用的,并且@Component也需要指定了该Module的时候。
@Module是告诉Component,可以从这里获取依赖对象。Component就会去找被@Provide标注的方法,相当于构造器的@Inject,可以提供依赖。
还有一点要说的是,@Component可以指定多个@Module的,如果需要提供多个依赖的话。
如下,将代码稍微修改:
注意此错误
dagger2XXX cannot be provided without an @Inject constructor or from an @Provides-annotated
public abstract class Flower { abstract String whisper(); }

public class Lily extends Flower { @Override public String whisper() { return "My lover Lily"; } }

public class Rose extends Flower { @Inject public Rose() { }@Override public String whisper() { return "My lover Rose"; } }

@Module public class FlowerModule {@Provides Flower provideRose() { return new Rose(); }@Provides Pot providePot() { return new Pot(new Lily()); }}

@Component(modules = {DaggeActivityModule.class,FlowerModule.class}) public interface DaggerActivityComp { void inject(DaggerActivity daggerActivity); }//打印如下

/ming.com.andcode D/DaggerActivity:pot.show() is :My lover Lily /ming.com.andcode D/DaggerActivity:rose is :My lover Rose /ming.com.andcode D/DaggerActivity:flower is :ming.com.andcode.dagger2.delo.Rose@1ec13658 /ming.com.andcode D/DaggerActivity:okHttpClient.toString() is :ming.com.andcode.dagger2.delo.OkHttpClient@16e323b1 /ming.com.andcode D/DaggerActivity:retrofitManager.getOkHttpClient().toString() is :ming.com.andcode.dagger2.delo.OkHttpClient@3f7c5096

@Qualifier和@Named @Qualifier是限定符,而@Named则是基于String的限定符。
当我有两个相同的依赖(都继承某一个父类或者都是先某一个接口)可以提供给高层时,那么程序就不知道我们到底要提供哪一个依赖,因为它找到了两个。
这时候我们就可以通过限定符为两个依赖分别打上标记,指定提供某个依赖。
我们修改以下代码,使FlowerModule提供两个Flower与一个Pot
@Module public class FlowerModule {@Provides Flower provideRose() { return new Rose(); }@Provides Flower provideLily() { return new Lily(); }@Provides Pot providePot() { return new Pot(new Lily()); }}

编译报错:
错误: [Dagger/DuplicateBindings] ming.com.andcode.dagger2.delo.Flower is bound multiple times: public interface DaggerActivityComp { ^ @Provides ming.com.andcode.dagger2.delo.Flower ming.com.andcode.dagger2.module.FlowerModule.provideLily() @Provides ming.com.andcode.dagger2.delo.Flower ming.com.andcode.dagger2.module.FlowerModule.provideRose() ming.com.andcode.dagger2.delo.Flower is injected at ming.com.andcode.dagger2.DaggerActivity.flower ming.com.andcode.dagger2.DaggerActivity is injected at ming.com.andcode.dagger2.component.DaggerActivityComp.inject(ming.com.andcode.dagger2.DaggerActivity)

@Qualifier的作用和@Named是完全一样的,不过更推荐使用@Qualifier,因为@Named需要手写字符串,容易出错。@Qualifier不是直接注解在属性上的,而是用来自定义注解的。
@Qualifier @Retention(RetentionPolicy.RUNTIME) public @interface LilyFlower { }

@Qualifier @Retention(RetentionPolicy.RUNTIME) public @interface RoseFlower { }

@Module public class FlowerModule {@Provides @RoseFlower Flower provideRose() { return new Rose(); }@Provides @LilyFlower Flower provideLily() { return new Lily(); }}

public class Pot { private Flower flower; @Inject public Pot(@RoseFlower Flower mRose) { this.flower = mRose; }public String show() { return flower.whisper(); } }

Component依赖Component
当我们其中一个Component跟另外一个Component所提供的依赖有重复的时候,我们没有必要完全再写一遍,一个Component是可以依赖另外一个依赖的,理解起来就像extends关键字;
有两种实现方式:dependence和@SubComponent
SubComponent和Dependence区别
Component dependencies - Use this when you want to keep two components independent.
Subcomponents - Use this when you want to keep two components coupled.
a、dependence方式
PotModule需要依赖LilyFlower,需要指定其中一个子类实现,这里使用LilyFlower
@Module public class PotModule {@Provides Pot providePot(@LilyFlower Flower flower) { return new Pot(flower); } }

@Component(modules = FlowerModule.class) public interface FlowerComponent { @RoseFlower Flower getRoseFlower(); @LilyFlower Flower getLilyFlower(); }

@Component(modules = PotModule.class, dependencies = FlowerComponent.class) public interface PotComponent { Pot getPot(); }

@Component(modules = {DaggeActivityModule.class},dependencies = PotComponent.class) public interface DaggerActivityComp { void inject(DaggerActivity daggerActivity); }

而在MainActivity则需要创建其依赖的Component
public class DaggerActivity extends AppCompatActivity { private static final String TAG = "DaggerActivity"; @Inject Rose rose; @Inject Pot pot; @Inject OkHttpClient okHttpClient; @Inject RetrofitManager retrofitManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_dagger); // 这个类是重新编译后Dagger2自动生成的,所以写这行代码之前要先编译一次 Build --> Rebuild Project DaggerDaggerActivityComp.builder().potComponent(DaggerPotComponent.builder().flowerComponent(DaggerFlowerComponent.create()).build()). daggeActivityModule(new DaggeActivityModule(3000)).build().inject(this); //创建其依赖的Component toastWhisper(); }private void toastWhisper() { Log.d(TAG, " rose is :" + rose.whisper()); Log.d(TAG, " pot is :" + pot.show()); Log.d(TAG, " okHttpClient.toString() is :" + okHttpClient.toString()); Log.d(TAG, " retrofitManager.getOkHttpClient().toString() is :" + retrofitManager.getOkHttpClient().toString()); }}

打印结果如下
ming.com.andcode D/DaggerActivity:rose is :My lover Rose ming.com.andcode D/DaggerActivity:pot is :My lover Lily ming.com.andcode D/DaggerActivity:okHttpClient.toString() is :ming.com.andcode.dagger2.delo.OkHttpClient@1ec13658 ming.com.andcode D/DaggerActivity:retrofitManager.getOkHttpClient().toString() is :ming.com.andcode.dagger2.delo.OkHttpClient@16e323b1

dependence实现方式总结:
1、父Component中要显式的写出需要暴露可提供给子Component的依赖;
2、子Component在注解中使用dependencies=来连接父Component;
3、注意子Component实例化方式。
b、Subcomponent方式
@Component(modules = FlowerModule.class) public interface FlowerComponent { PotComponent plus(PotModule potModule); }

@Subcomponent(modules = PotModule.class) public interface PotComponent { DaggerActivityComp plus(); }

@Subcomponent public interface DaggerActivityComp { void inject(DaggerActivity daggerActivity); }

public class DaggerActivity extends AppCompatActivity { private static final String TAG = "DaggerActivity"; @Inject Pot pot; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_dagger); // 这个类是重新编译后Dagger2自动生成的,所以写这行代码之前要先编译一次 Build --> Rebuild Project DaggerFlowerComponent.create(). plus(new PotModule())// 这个方法返回PotComponent .plus()// 这个方法返回MainActivityComponent .inject(this); toastWhisper(); }private void toastWhisper() { Log.d(TAG, " pot is :" + pot.show()); } }

打印结果:
/ming.com.andcode D/DaggerActivity:pot is :My lover Lily

subComponent实现方式总结:
1、在子Component,定义一个接口或抽象类(通常定义为xxBuilder),使用@Subcomponent.Builder标注:
? (一)、编写返回值为xxBuilder,方法的参数为需要传入参数的Module,(二)、编写返回值为当前子Component的无参方法;
2、父Component中定义获得子Component.Builder的方法;
FlowerComponent管理了PotComponent和DaggerActivityComp,看起来不符合常理。
但是用Subcomponent怎么看怎么别扭,各个Component之间联系太紧密,不太适合我们Demo的使用场景。
那什么时候该用@Subcomponent呢?
Subcomponent是作为Component的拓展的时候。
像我写的Demo中,Pot和Flower还有MainActivity只是单纯的依赖关系。就算有,也只能是Flower作为Pot的Subcomponent,而不是Demo中所示,因为我需要给大家展示Dagger的API,强行使用。
比较适合使用Subcomponent的几个场景:
很多工具类都需要使用到Application的Context对象,此时就可以用一个Component负责提供,我们可以命名为AppComponent。
需要用到的context对象的SharePreferenceComponent,ToastComponent就可以它作为Subcomponent存在了。
而且在AppComponent中,我们可以很清晰的看到有哪些子Component,因为在里面我们定义了很多XxxComponent plus(Module... modules)
每个ActivityComponent也是可以作为AppComponent的Subcomponent,这样可以更方便的进行依赖注入,减少重复代码。
Component dependencies和Subcomponent使用上的总结
Dependencies:
  • 1,你想保留独立的想个组件(Flower可以单独使用注入,Pot也可以)
  • 2,要明确的显示该组件所使用的其他依赖
Subcomponent:
  • 1,两个组件之间的关系紧密
  • 2,你只关心Component,而Subcomponent只是作为Component的拓展,可以通过Component.xxx调用。
@Scope和@Singleton
@Scope是用来管理依赖的生命周期的。它和@Qualifier一样是用来自定义注解的,而@Singleton则是@Scope的默认实现。
public class DaggerActivity extends AppCompatActivity { private static final String TAG = "DaggerActivity"; @Inject Pot pot; @Inject Pot poti; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_dagger); // 这个类是重新编译后Dagger2自动生成的,所以写这行代码之前要先编译一次 Build --> Rebuild Project DaggerDaggerActivityComp.builder().potComponent(DaggerPotComponent.builder().flowerComponent(DaggerFlowerComponent.create()).build()). daggeActivityModule(new DaggeActivityModule(3000)).build().inject(this); toastWhisper(); }private void toastWhisper() {Log.d(TAG, " potis:" + pot.show()+" pot hashcode is "+pot.hashCode()); Log.d(TAG, " potiis:" + poti.show()+" poti hashcode is "+poti.hashCode()); }}

打印结果:
ming.com.andcode D/DaggerActivity:potis:My lover Lily pot hashcode is 515978840 /ming.com.andcode D/DaggerActivity:potiis:My lover Lily poti hashcode is 383984561

假设我们需要Pot对象的生命周期和app相同,也就是单例,我们需要怎么做?这时候就可以用到@Scope注解了。
我们来使用默认的@Scope实现——@Singleton
a、无Module的使用方式,只需提供依赖的类及Component都添加@Singleton标注即可;
b、如果是带Module的,Component必须添加@Singleton标注,然后再根据需要给Module中@provides标注的方法再标注上@Singleton
@Module public class PotModule {@Provides @Singleton Pot providePot(@LilyFlower Flower flower) { return new Pot(flower); } }

@Singleton @Component(modules = PotModule.class, dependencies = FlowerComponent.class) public interface PotComponent { Pot getPot(); }

错误: ming.com.andcode.dagger2.component.DaggerActivityComp (unscoped) cannot depend on scoped components: @Component(modules = {DaggeActivityModule.class},dependencies = PotComponent.class) ^ @Singleton ming.com.andcode.dagger2.component.PotComponent

那么,我们在PotComponent子类DaggerActivityComp添加@Singleton呢?
1,PotComponent无@Singleton,DaggerActivityComp添加@Singleton
错误: [Dagger/IncompatiblyScopedBindings] ming.com.andcode.dagger2.component.PotComponent (unscoped) may not reference scoped bindings: public interface PotComponent { ^ @Provides @Singleton ming.com.andcode.dagger2.delo.Pot ming.com.andcode.dagger2.module.PotModule.providePot(@ming.com.andcode.dagger2.qualifier.LilyFlower ming.com.andcode.dagger2.delo.Flower)

2,PotComponent有@Singleton,DaggerActivityComp有@Singleton
错误: This @Singleton component cannot depend on scoped components: @Component(modules = {DaggeActivityModule.class},dependencies = PotComponent.class) ^ @Singleton ming.com.andcode.dagger2.component.PotComponent

【浅入浅出Dagger2|浅入浅出Dagger2 — 基本使用与理解篇】那是因为我们的DaggerActivityComp依赖PotComponent,而dagger2规定子Component也必须标注@Scope。
但是我们不能给DaggerActivityComp也标注@Singleton,并且dagger2也不允许。因为单例依赖单例是不符合设计原则的,我们需要自定义一个@Scope注解。
定义Scope是名字要起得有意义,能一眼就让你看出这个Scope所规定的生命周期。
比如ActivityScope 或者PerActivityScope,生命周期和Activity相同。
/** * Identifies a type that the injector only instantiates once. Not inherited. * * @see javax.inject.Scope @Scope */ @Scope @Documented @Retention(RUNTIME) public @interface Singleton {}

仿照Singleton,我们自己定义Scope
/** * Identifies a type that the injector only instantiates once. Not inherited. * * @see javax.inject.Scope @Scope */ @Scope @Documented @Retention(RUNTIME) public @interface ActivityScope {}

将自定义Scope引入
@ActivityScope @Component(modules = {DaggeActivityModule.class},dependencies = PotComponent.class) public interface DaggerActivityComp { void inject(DaggerActivity daggerActivity); }

private void toastWhisper() {Log.d(TAG, " potis:" + pot.show()+" pot hashcode is "+pot.hashCode()); Log.d(TAG, " potiis:" + poti.show()+" poti hashcode is "+poti.hashCode()); }

打印相同的数据,美滋滋。
这时候我们看到两个pot对象的hashcode值是一样的,@Scope注解起作用了。
关于Scope要注意的:
1、把Scope简单的解释为单例还是不科学的,只是我们刚开始接触的时候使用@Singleton从而觉得它就是单例,其实正确的理解应该是:在某个范围里它是单例(何为作用域呢,可以看作是我们在程序中实例化的Component的生命周期的长短:如果在Application里build的那它的作用域就是整个App的生命周期,如果是在Acitivity中build的那它的作用域就跟此Acitivity的生命周期相同,如上文代码中的ActivityScope将Pot注入另一个activity,pot.hashcode会再次改变);
2、Scope只是一个标注,跟它的名字无关,跟它使用的地方及Component实例化的地方有关,Scope在很大程度上是为了方便阅读代码;
3、在Component依赖Component的时候,Scope的名字必须是不同的,这就需要自定义Scope。
  • @Component的dependencies与@Component自身的scope不能相同,即组件之间的scope不能相同,否则出现下面错误。
  • 而在Component中标注@Scope,provide方法没有标注,那么这个Scope就不会起作用,而Component上的Scope的作用也只是为了能顺利通过编译,就像我刚刚定义的ActivityScope一样。
  • @Singleton的组件不能依赖其他scope的组件,但是其他scope的组件可以依赖@Singleton组件。
  • 没有scope的不能依赖有scope的组件。
那么,我们如何使用Dagger2实现单例呢? 很简单,做到以下两点即可。
  • 依赖在Component中是单例的(供该依赖的provide方法和对应的Component类使用同一个Scope注解。)
  • 对应的Component在App中只初始化一次,每次注入依赖都使用这个Component对象。(在Application中创建该Component)
    上代码
    修改app中AndApplication
    public class AndApplication extends Application { private PotComponent potComponent; @Override public void onCreate() { super.onCreate(); initializeARouter(); initializePotComponent(); }private void initializePotComponent() {//PotComponent位全局变量,且只有一个 potComponent = DaggerPotComponent.builder() .flowerComponent(DaggerFlowerComponent.create()) .build(); }public PotComponent getPotComponent() { return potComponent; } }

    Activity注入代码改为即可
    DaggerDaggerActivityComp.builder().potComponent(( (AndApplication) getApplication()).getPotComponent()). daggeActivityModule(new DaggeActivityModule(3000)).build().inject(this);

现在Pot的生命周期就和app相同了。
总结
1、Module并不是必需的,但Component是必不可少的;
2、编译后生成的Component实现类的名称是Dagger+我们所定义的Component接口的名称。
3、Dagger2的依赖注入思想重在理解,希望小白们上手以后不单单是在使用它,更重要的是要理解它;Dagger2还有很多其他花式用法,比如在文里提到的一个Module两个方法返回值相同,还有懒加载等等,希望大家自己研究一下,以防不时之需。
在使用dagger2的过程中,在定义一些类或方法的名字的时候,要遵守一些谷歌提出的固定标准,以方便代码阅读与维护:
1、定义的Component和Module的名字是无所谓的,但是一般遵照以Component或Module结尾的名称;
2、Module中用@Provides标注的方法的方法名是无所谓的,返回值是最重要的,但是一般遵照以provide开头的方法名;
3、Component中返回值为void且有参的方法,方法名是无所谓的,参数是最重要的代表的是要注入的目标位置,但是方法名一般为inject;
4、Component中返回值不为void且无参的方法,方法名是无所谓的,返回值是最重要的代表的是暴露给子Component使用的依赖或者是获取的子Component的类型。
参考博文:
1,可能是东半球最好的dagger2文章
2, 浅析Dagger2的使用

    推荐阅读