Osheep

时光不回头,当下最重要。

我所理解的Dagger2

一、简述

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

《我所理解的Dagger2》

<!– more –>

二、注解方法

  1. @Inject: 通常在需要依赖的地方使用这个注解。换句话说,你用它告诉Dagger这个类或者字段需要依赖注入。这样,Dagger就会构造一个这个类的实例并满足他们的依赖。

  2. @Module: Modules类里面的方法专门提供依赖,所以我们定义一个类,用 @Module注解,这样Dagger在构造类的实例的时候,就知道从哪里去找到需要的 依赖。modules的一个重要特征是它们设计为分区并组合在一起(比如说,在我们的app中可以有多个组成在一起的modules)。

  3. @Provides: 在modules中,我们定义的方法是用这个注解,以此来告诉Dagger我们想要构造对象并提供这些依赖。

  4. @Component: Components从根本上来说就是一个注入器,也可以说是@Inject@Module的桥梁,它的主要作用就是连接这两个部分。Components可以提供所有定义了的类型的实例,比如:我们必须用@Component注解一个接口然后列出所有的@Modules组成该组件,如 果缺失了任何一块都会在编译的时候报错。所有的组件都可以通过它的modules知道依赖的范围。

  5. @Named:当有多个构造方法时,可以使用@Named进行标记区分

  6. @Scope: Scopes可是非常的有用,Dagger2可以通过自定义注解限定注解作用域。后面会演示一个例子,这是一个非常强大的特点,因为就如前面说的一样,没必要让每个对象都去了解如何管理他们的实例

  7. @Singleton:单例

三、入门例子

  1. 创建两个实例类

     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);
         }
     }
  2. 创建Component,连接Module与Activity之间的桥梁

     // @Modules 类似于我们的模块,提供各种实例跟对象
     @Module
     public class UserModule {
    
         private Context mContext;
         private String s;
    
         public UserModule(Context context,String s) {
             this.mContext = context;
             this.s = s;
         }
    
         // @Provides 在Modules中,我们定义的方法是用这个注解,以此来告诉Dagger2我们想要提供哪些实例和对象
         @Provides
         public OrderController providerOrderController() {
             return new OrderController("lisi");
         }
    
         @Provides
         public MoneyController providerMoneyController() {
             return new MoneyController(s);
         }
     }
  3. Inject注入

     // @Component:注入器,是@Inject和@Module的桥梁,它的主要作用就是连接这两个部分
     @Component(modules = {UserModule.class})
     public interface UserComponet {
         void inject(DaggerActivity daggerActivity);
     }
  4. 在Activity中使用(需要先Rebuild一下,会自动生成一个Dagger开头的类)

@Inject
OrderController orderController;
@Inject
MoneyController moneyController;
---------------------------------
// 需要传参必须要用builder构建
DaggerUserComponet.builder().userModule(new UserModule(this,"sss")).build().inject(this);

// 如果构造方法中不需要参数可以直接用
// DaggerUserComponet.create()

btnMakeCoffee.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        tvCoffee.setText(moneyController.payMoney());
        orderController.order();
    }
});
  1. 如果UserModule中没有提供providerMoneyController这个方法可以怎么做呢?

它会自动调用MoneyController类中带有@Inject注解的构造方法

四、区分不同实例

如果一个类有两个或多个构造方法该如何去区分使用呢?使用`@Named`
  1. 修改一下OrderController,给它添加一个构造方法

     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);
         }
     }
  2. 修改UserModule,使用@Named方法进行标记

     // @Named 有多个构造方法时使用它标注不同的名字
     // @Provides 在Modules中,我们定义的方法是用这个注解,以此来告诉Dagger2我们想要提供哪些实例和对象
     @Named("debug")
     @Provides
     public OrderController providerOrderController() {
         return new OrderController("lisi");
     }
    
     @Named("release")
     @Provides
     public OrderController providerUserControllerNameAndAge() {
         return new OrderController("lisi", 15);
     }
  3. 在Activity中也要这样子标注一下

     @Named("debug")
     @Inject
     OrderController orderController1;
     @Named("release")
     @Inject
     OrderController orderController2;
  4. 如果不满足这样子处理,可以参照源码加一个自定义注解

     @Qualifier
     @Documented
     @Retention(RUNTIME)
     public @interface Debug {
     }
  5. 用4中的注解取代@Named("debug")

     @Debug
     @Provides
     public OrderController providerOrderController() {
         return new OrderController("lisi");
     }
    
     ----------------
    
     @Debug
     @Inject
     OrderController orderController1;

五、模块化的三种方式

  1. 假设单独创建一个网络请求的OkHttp模块,MoneyController需要使用这个OkHttpClient

     @Module
     public class HttpModule {
    
         // 在这里创建OkHttpClient(应该是用单例的)
         @Provides
         public OkHttpClient providerOkHttpClient(){
             return new OkHttpClient().newBuilder().build();
         }
     }
  2. 使用@Module(includes = HttpModule.class)引入

     @Module(includes = HttpModule.class)
     public class UserModule {
    
         ... ...
    
         // OkHttpClient来自HttpModule
         @Provides
         public MoneyController providerMoneyController(OkHttpClient okHttpClient) {
             return new MoneyController(okHttpClient);
         }
     }
  3. 在Activity中使用

     DaggerUserComponet.builder()
             .userModule(new UserModule(this))
             .httpModule(new HttpModule()) //注意这个地方
             .build().inject(this);
  4. 第二种方法:可以将HttpModule.class添加到UserComponet的@Component注解的modules中

     @Component(modules = {UserModule.class, HttpModule.class})
  5. 第三种方法是使用dependencies引入一个Component

     @Component(dependencies =HttpComponent.class, modules = UserModule.class)

六、在Kotlin中使用Dagger2(修改项目build)

apply plugin: 'kotlin-kapt'
... ...
kapt {
    generateStubs = true
}
... ...
dependencies {
    // 使用kapt
    // dagger2
    compile "com.google.dagger:dagger:$dagger_version"
    kapt "com.google.dagger:dagger-compiler:$dagger_version"
}

七、全局单例(使用Kotlin实现)

声明:例子比较复杂,可以看源码(KotlinAndroidSamples),这里简要列举一下代码

  1. AppComponent

     @Singleton
     @Component(modules = arrayOf(AppModule::class, HttpModule::class))
     interface AppComponent {
    
         fun getContext(): App   // 提供App的Context
    
         fun getDataManager(): DataManager  //数据中心
    
         fun retrofitHelper(): RetrofitHelper   //提供http的帮助类
    
     }
  2. App(继承自Application)

     class App : Application() {
    
         // 伴生对象
         companion object {
             lateinit var appComponent: AppComponent
         }
    
         override fun onCreate() {
             super.onCreate()
    
             appComponent = DaggerAppComponent
                     .builder()
                     .appModule(AppModule(this))
                     .httpModule(HttpModule())
                     .build()
         }
    
     }
  3. 在其它地方使用appComponent

     DaggerFragmentComponent
             .builder()
             .appComponent(App.appComponent)
             .fragmentModule(FragmentModule(this))
             .build()
             .inject(this)
  4. FragmentComponent

     @FragmentScope
     @Component(dependencies = arrayOf(AppComponent::class), modules = arrayOf(FragmentModule::class))
     interface FragmentComponent {
    
         val activity: Activity
    
         fun inject(mingJiaFragment: MingJiaFragment)
     }

八、源码地址

例子源码:https://github.com/sdwfqin/AndroidSamples
Kotlin例子源码:https://github.com/sdwfqin/KotlinAndroidSamples

点赞