ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] 推荐两篇Dagger2学习教程:[《Dagger2 入门,以初学者角度》](https://www.jianshu.com/p/1d84ba23f4d2)和[《Android:dagger2让你爱不释手-基础依赖注入框架篇》](https://www.jianshu.com/p/cd2c1c9f68d4) # 学习总结 ## 总览 1、Java 中万物皆对象,每一个对象可以拥有很多成员变量,这些成员变量可以是各种对象 2、依赖注入,顾名思义指一个类所依赖的对象的注入过程,省去了手动去为一个对象 new 一堆依赖的过程 3、Module 是依赖提供方,Activity、Fragment 等是依赖需求方,Component 是依赖注入器 4、Component 是一个接口,编译代码后,会自动生成一个实现类 ## 工作流程 1、调用 Component 实现类的 inject 方法,把依赖需求方对象(比如 Activity 自身),传递给 Component 2、Component 根据依赖需求方的需求,从 Module 中寻找现成的实例对象,并注入给依赖需求方(Activity) ## 关键注解说明 ### @Component 一个标注的 @Component 注解形式如下: ```java @Component(dependencies = AppComponent.class,modules = {MainModule.class, ActivityModule.class}) public interface MainComponent extends ActivityComponent{ ... } ``` @Component 注解有两个属性:dependencies 和 modules。dependencies 属性声明 @Component 的依赖关系,modules 属性声明 @Component 后期会从哪些 @Module 中去寻找依赖实例。 我们在 创建 @Component 的实现类对象时,需要提供父 Component 实例对象和 Module 实例对象,如下: ```java mMainComponent = DaggerMainComponent.builder().appComponent(getAppComponent()) .mainModule(new MainModule()) .activityModule(new ActivityModule(this)).build(); mMainComponent.inject(this); ``` ### @Scope Scope 的意思是“范围”,即用来声明依赖对象作用范围的 > Dagger2 有一个机制:在同一个作用范围内,@Provides 方法提供的依赖对象会变成单例。即依赖需求方不管依赖几次 @Provides 提供的对象,Dagger2 都会只调用一次该 @Provides 方法来获取依赖实例,后期再需要该依赖实例时直接进行提供。 @Scope 注解需要自定义注解才可以使用,@Singleton 就是一个自定义注解: ```java @Scope @Documented @Retention(RUNTIME) public @interface Singleton {} ``` 依赖提供方 Module 的 @Provides 方法使用 @Singleton 注解声明,依赖注入器 Component 也使用 @Singleton 注解声明即可。这样 Module 提供的依赖对象就是单例的了。 ### @Qulifier Dagger2 是通过返回值类型来从 Module 中获取依赖对象的。也就是说像如下的 Module 代码中,Component 并不知道该调用哪一个方法来生成对象: ```java @Provides public Cloth getRedCloth() { Cloth cloth = new Cloth(); cloth.setColor("红色"); return cloth; } @Provides public Cloth getBlueCloth() { Cloth cloth = new Cloth(); cloth.setColor("蓝色"); return cloth; } ``` 所以需要一个 Qulifier 注解来进行区分: ```java @Qualifier @Retention(RetentionPolicy.RUNTIME) public @interface RedCloth { } @Qualifier @Retention(RetentionPolicy.RUNTIME) public @interface BlueCloth { } ``` 使用 @RedCloth 和 @BlueCloth 对依赖需求方和依赖提供方进行注解,便可进行区分 # 源码分析 ## 注解 Dagger2 的工作主要是通过注解来实现的,所以理解注解至关重要,这里推荐一篇讲解注解很清晰的文章:[秒懂,Java 注解 (Annotation)你可以这样学](https://blog.csdn.net/briblue/article/details/73824058) ## 注解处理器 和 EventBus、ButterKnife 一样,Dagger2 也是通过注解处理器来在编译器进行代码生成,关于注解处理器可以参考我的另一篇博文:[EventBus 3.0 源码分析(二)注解处理器的使用](http://xuchongyang.com/2017/07/17/EventBus-3-0-%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90%EF%BC%88%E4%BA%8C%EF%BC%89%E7%BC%96%E8%AF%91%E6%97%B6%E6%B3%A8%E8%A7%A3%E5%92%8C%E8%BF%90%E8%A1%8C%E6%97%B6%E6%B3%A8%E8%A7%A3/)。 ## 源码分析 我们先来定义一个最简单的 Dagger2 的使用实例: MainActivity 类如下: ```java public class MainActivity extends AppCompatActivity { @Inject public Computer mComputer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MainComponent mainComponent = DaggerMainComponent.builder() .mainModule(new MainModule()) .build(); mainComponent.inject(this); } } ``` @Module 类如下: ```java @Module public class MainModule { @Provides public Computer providesAppleComputer() { return new Computer("Apple"); } } ``` @Component 类如下: ```java @Component(modules = MainModule.class) public interface MainComponent { void inject(MainActivity activity); } ``` 然后点击 rebuild project 进行编译。我这边在第一次进行代码编译时,并没有如预期生成 @Component 的实现类,发现由于 Dagger2 的引入是在 子 Module 中引入的,因此在 app 模块中注解处理器无法为我们生成代码。只要在主模块引入注解处理器即可: ```plain annotationProcessor 'com.google.dagger:dagger-compiler:2.15' ``` 在 MainActivity 代码中可以看到,我们先通过 Component 的实现类的 builder 模式获取到实例对象,再调用 inject 方法进行依赖注入。注入成功后此时 MainActivity 的成员变量就已经赋值了。 我们看看 Component 的实现类 DaggerMainComponent 的源码: ```java public final class DaggerMainComponent implements MainComponent { private MainModule mainModule; private DaggerMainComponent(Builder builder) { initialize(builder); } public static Builder builder() { return new Builder(); } public static MainComponent create() { return new Builder().build(); } @SuppressWarnings("unchecked") private void initialize(final Builder builder) { this.mainModule = builder.mainModule; } @Override public void inject(MainActivity activity) { injectMainActivity(activity); } private MainActivity injectMainActivity(MainActivity instance) { MainActivity_MembersInjector.injectMComputer( instance, MainModule_ProvidesAppleComputerFactory.proxyProvidesAppleComputer(mainModule)); return instance; } public static final class Builder { private MainModule mainModule; private Builder() {} public MainComponent build() { if (mainModule == null) { this.mainModule = new MainModule(); } return new DaggerMainComponent(this); } public Builder mainModule(MainModule mainModule) { this.mainModule = Preconditions.checkNotNull(mainModule); return this; } } } ``` 代码精简一下,其实也很简单,仅仅是一个标准的 builder 模式,外加实现了 Component 接口的 inject 方法: ```java public final class DaggerMainComponent implements MainComponent { private MainModule mainModule; public static Builder builder() { return new Builder(); } // ... @Override public void inject(MainActivity activity) { injectMainActivity(activity); } public static final class Builder { // ... } } ``` 接下来我们一一看: **1、Component使用Builder模式创建Module成员变量** 首先是 builder 模式的 build 方法: ```java public MainComponent build() { if (mainModule == null) { this.mainModule = new MainModule(); } return new DaggerMainComponent(this); } ``` ```java private DaggerMainComponent(Builder builder) { initialize(builder); } ``` ```java @SuppressWarnings("unchecked") private void initialize(final Builder builder) { this.mainModule = builder.mainModule; } ``` 很好理解,其实就是给 DaggerMainComponent 的成员变量 mainModule 对象进行赋值操作。接下来看看比较关键的注入操作: **2、Component为待注入对象进行依赖注入** ```java @Override public void inject(MainActivity activity) { injectMainActivity(activity); } ``` ```java private MainActivity injectMainActivity(MainActivity instance) { MainActivity_MembersInjector.injectMComputer( instance, MainModule_ProvidesAppleComputerFactory.proxyProvidesAppleComputer(mainModule)); return instance; } ``` 可以看到,注入操作是调用了 MainActivity_MembersInjector 这个类的 injectMComputer 方法,看看这个方法: ```java // MainActivity_MembersInjector.java public static void injectMComputer(MainActivity instance, Computer mComputer) { instance.mComputer = mComputer; } ``` 在 injectMComputer 方法中,直接把第二个参数 Computer 对象赋值给依赖需求方 MainActivity。MainActivity 是我们直接手动传递过来的,那么第二个参数的依赖对象是怎么来的呢,也就是 `MainModule_ProvidesAppleComputerFactory.proxyProvidesAppleComputer(mainModule)` 这一行代码是如何拿到一个目标依赖对象的呢? 编译时 Dagger2 自动为我们生成了 MainModule_ProvidesAppleComputerFactory 这个类,看名称就知道是提供 AppleComputer 的工厂类,对应着我们 MainModule 中的 providesAppleComputer。看看 proxyProvidesAppleComputer 方法: ```java // MainModule_ProvidesAppleComputerFactory.java public static Computer proxyProvidesAppleComputer(MainModule instance) { // 此处做一下非空判断 return Preconditions.checkNotNull( instance.providesAppleComputer(), "Cannot return null from a non-@Nullable @Provides method"); } ``` 参数 MainModule 就是刚才在 builder 方法中初始化的那个 MainModule。最终返回的是 MainModule 的 providesAppleComputer 方法所提供的实例对象。至此,Component 就完成了从 Module 中获取依赖实例对象,并注入到依赖需求方的过程。 ## 总结 1、Component的实现类采用Builder模式,完成Component成员变量Module的设置。 2、Component实现类的inject方法,参数为等待注入的对象(如Activity等),将Module提供的对象设置给等待注入的对象。