一、简述
Dagger2是一个Android目前较为主流的依赖注入框架,最早的版本Dagger1 由Square公司开发,现在Dagger2由谷歌接手开发,主要用于模块间解耦,提高代码的健壮性和可维护性。之前也断断续续看过好多文章,今天正式学习一下。并且额外介绍下如何在Kotlin中使用Dagger2,写的不好,还请见谅!

二、注解方法
- @Inject: 通常在需要依赖的地方使用这个注解。换句话说,你用它告诉Dagger这个类或者字段需要依赖注入。这样,Dagger就会构造一个这个类的实例并满足他们的依赖。
- @Module: Modules类里面的方法专门提供依赖,所以我们定义一个类,用- @Module注解,这样Dagger在构造类的实例的时候,就知道从哪里去找到需要的 依赖。modules的一个重要特征是它们设计为分区并组合在一起(比如说,在我们的app中可以有多个组成在一起的modules)。
- @Provides: 在modules中,我们定义的方法是用这个注解,以此来告诉Dagger我们想要构造对象并提供这些依赖。
- @Component: Components从根本上来说就是一个注入器,也可以说是- @Inject和- @Module的桥梁,它的主要作用就是连接这两个部分。Components可以提供所有定义了的类型的实例,比如:我们必须用- @Component注解一个接口然后列出所有的- @Modules组成该组件,如 果缺失了任何一块都会在编译的时候报错。所有的组件都可以通过它的modules知道依赖的范围。
- @Named:当有多个构造方法时,可以使用- @Named进行标记区分
- @Scope: Scopes可是非常的有用,Dagger2可以通过自定义注解限定注解作用域。后面会演示一个例子,这是一个非常强大的特点,因为就如前面说的一样,没必要让每个对象都去了解如何管理他们的实例
- @Singleton:单例
三、入门例子
- 创建两个实例类 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23- public class MoneyController { 
 public MoneyController(String s) {
 Log.e("TAG", "MoneyController: 构造方法======" + s);
 }
 public String payMoney() {
 return "payMoney";
 }
 }
 // -------------------------------------------------
 public class OrderController {
 String s;
 public OrderController(String s) {
 this.s = s;
 }
 public void order() {
 Log.e("OrderController", "order" + s);
 }
 }
- 创建Component,连接Module与Activity之间的桥梁 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23- // @Modules 类似于我们的模块,提供各种实例跟对象 
 public class UserModule {
 private Context mContext;
 private String s;
 public UserModule(Context context,String s) {
 this.mContext = context;
 this.s = s;
 }
 // @Provides 在Modules中,我们定义的方法是用这个注解,以此来告诉Dagger2我们想要提供哪些实例和对象
 
 public OrderController providerOrderController() {
 return new OrderController("lisi");
 }
 
 public MoneyController providerMoneyController() {
 return new MoneyController(s);
 }
 }
- Inject注入 - 1 
 2
 3
 4
 5- // @Component:注入器,是@Inject和@Module的桥梁,它的主要作用就是连接这两个部分 
 public interface UserComponet {
 void inject(DaggerActivity daggerActivity);
 }
- 在Activity中使用(需要先Rebuild一下,会自动生成一个Dagger开头的类) 
| 1 | 
 | 
- 如果UserModule中没有提供providerMoneyController这个方法可以怎么做呢?
它会自动调用MoneyController类中带有@Inject注解的构造方法
四、区分不同实例
如果一个类有两个或多个构造方法该如何去区分使用呢?使用`@Named`
- 修改一下OrderController,给它添加一个构造方法 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22- public class OrderController { 
 String s;
 int age;
 public OrderController(String s) {
 this.s = s;
 }
 public OrderController(String s, int age) {
 this.s = s;
 this.age = age;
 }
 public void order() {
 Log.e("OrderController", "order" + s);
 }
 public void age() {
 Log.e("OrderController", "order" + s + "age" + age);
 }
 }
- 修改 - UserModule,使用- @Named方法进行标记- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13- // @Named 有多个构造方法时使用它标注不同的名字 
 // @Provides 在Modules中,我们定义的方法是用这个注解,以此来告诉Dagger2我们想要提供哪些实例和对象
 public OrderController providerOrderController() {
 return new OrderController("lisi");
 }
 public OrderController providerUserControllerNameAndAge() {
 return new OrderController("lisi", 15);
 }
- 在Activity中也要这样子标注一下 - 1 
 2
 3
 4
 5
 6
 OrderController orderController1;
 OrderController orderController2;
- 如果不满足这样子处理,可以参照源码加一个自定义注解 - 1 
 2
 3
 4
 5
 public Debug {
 }
- 用4中的注解取代 - @Named("debug")- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 public OrderController providerOrderController() {
 return new OrderController("lisi");
 }
 ----------------
 OrderController orderController1;
五、模块化的三种方式
- 假设单独创建一个网络请求的OkHttp模块,MoneyController需要使用这个OkHttpClient - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 public class HttpModule {
 
 // 在这里创建OkHttpClient(应该是用单例的)
 
 public OkHttpClient providerOkHttpClient(){
 return new OkHttpClient().newBuilder().build();
 }
 }
- 使用 - @Module(includes = HttpModule.class)引入- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 public class UserModule {
 ... ...
 // OkHttpClient来自HttpModule
 
 public MoneyController providerMoneyController(OkHttpClient okHttpClient) {
 return new MoneyController(okHttpClient);
 }
 }
- 在Activity中使用 - 1 
 2
 3
 4- DaggerUserComponet.builder() 
 .userModule(new UserModule(this))
 .httpModule(new HttpModule()) //注意这个地方
 .build().inject(this);
- 第二种方法:可以将 - HttpModule.class添加到UserComponet的- @Component注解的modules中- 1 
- 第三种方法是使用dependencies引入一个Component - 1 
六、在Kotlin中使用Dagger2(修改项目build)
| 1 | apply plugin: 'kotlin-kapt' | 
七、全局单例(使用Kotlin实现)
声明:例子比较复杂,可以看源码(KotlinAndroidSamples),这里简要列举一下代码
- AppComponent - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 )
 interface AppComponent {
 fun getContext(): App // 提供App的Context
 fun getDataManager(): DataManager //数据中心
 fun retrofitHelper(): RetrofitHelper //提供http的帮助类
 }
- App(继承自Application) - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18- class App : Application() { 
 // 伴生对象
 companion object {
 lateinit var appComponent: AppComponent
 }
 override fun onCreate() {
 super.onCreate()
 appComponent = DaggerAppComponent
 .builder()
 .appModule(AppModule(this))
 .httpModule(HttpModule())
 .build()
 }
 
 }
- 在其它地方使用appComponent - 1 
 2
 3
 4
 5
 6- DaggerFragmentComponent 
 .builder()
 .appComponent(App.appComponent)
 .fragmentModule(FragmentModule(this))
 .build()
 .inject(this)
- FragmentComponent - 1 
 2
 3
 4
 5
 6
 7
 8
 , modules = arrayOf(FragmentModule::class))
 interface FragmentComponent {
 val activity: Activity
 fun inject(mingJiaFragment: MingJiaFragment)
 }
八、源码地址
例子源码:https://github.com/sdwfqin/AndroidSamples
Kotlin例子源码:https://github.com/sdwfqin/KotlinAndroidSamples