Dagger2使用

作者: YoKey | 来源:发表于2015-12-01 17:48 被阅读63588次

    在简单使用了一段时间的dagger2之后,来谈谈对dagger2浅薄的认知。

    首先,使用依赖注入可以带来哪些好处?

    1、依赖的注入和配置独立于组件之外,注入的对象在一个独立、不耦合的地方初始化,这样在改变注入对象时,我们只需要修改对象的实现方法,而不用大改代码库。

    2、依赖可以注入到一个组件中:我们可以注入这些依赖的模拟实现,这样使得测试更加简单。

    3、app中的组件不需要知道有关实例创建和生命周期的任何事情,这些由我们的依赖注入框架管理的。

    我觉得,dagger2这样的依赖注入框架对MVP架构来说,是最好的解耦工具,可以进一步降低modle-view-presenter之间的耦合度。
    所以,如果你的项目在使用MVP架构开发,强烈建议配合dagger2一起使用。

    接下来,在贴代码之前,我先说说明下我的MVP架构和传统的MVP有些不同,传统MVP的M层处理业务逻辑,P层仅仅是V和M的桥梁;而我的P层同时处理与model相关的业务逻辑,不处理View层次的逻辑,View层次的逻辑交给V自己处理,M层仅仅是bean,这种方式是根据开发中的实际情况而作的考虑,这里先不作讨论。

    先看结构图:


    接下来,分解这张图:
    AppComponent: 生命周期跟Application一样的组件。可注入到自定义的Application类中,@Singletion代表各个注入对象为单例。

    @Singleton
    @Component(modules = AppModule.class)
    public interface AppComponent {
        Context context();  // 提供Applicaiton的Context
    
        ThreadExecutor threadExecutor();   // 线程池
    
        ApiService apiService();  // 所有Api请求的管理类
    
        SpfManager spfManager();  // SharedPreference管理类
    
        DBManager dbManager();  // 数据库管理类
    }
    

    AppModule: 这里提供了AppComponent里的需要注入的对象。

    @Module
    public class AppModule {
        private final MyApplication application;
    
        public AppModule(MyApplication application) {
            this.application = application;
        }
    
        @Provides
        @Singleton
        Context provideApplicationContext() { 
           return application;
        }
    
        @Provides
        @Singleton
        ThreadExecutor provideThreadExecutor(JobExecutor jobExecutor) {
            return jobExecutor;
        }
    
        @Provides
        @Singleton
        ApiService providesApiService(RetrofitManager retrofitManager) {
            return retrofitManager.getService();
        }
    
        @Provides
        @Singleton
        SpfManager provideSpfManager() {
            return new SpfManager(application);
        }
    
        @Provides
        @Singleton
        DBManager provideDBManager() {
            return new DBManager(application);
        }
    }
    

    这里细心的童鞋可能发现,为何有些方法直接返回入参,有些需要返回一个new的对象呢?
    这里如果对DBManager的写法换成:

    DBManager provideDBManager(DBManager dbManager) {
      return dbManager;
    }
    

    这样编译不会通过,会报一个循环依赖的错误,这种写法需要在返回参数和入参是继承关系才可以。感兴趣的可以查看dagger2生成的代码。

    对于直接返回的类JobExecutor、RetrofitManager,它们类的构造函数一定要加上@Inject的注解:

    @Inject
    public JobExecutor() {
        // 初始化
        // ......
    }
    

    接下来谈谈ActivityComponent,可以看到有个@ActivityScope注解,这个注解是自定义的,对应Activity的生命周期,Dagger2可以通过自定义注解限定注解作用域。

    @Scope
    @Retention(RUNTIME)
    public @interface ActivityScope {}
    

    ActivityComponent:生命周期跟Activity一样的组件,这里提供了inject方法将Activity注入到ActivityComponent中,通过该方法,将Activity中需要注入的对象注入到该Activity中。

    @ActivityScope
    @Component(dependencies = AppComponent.class, modules = ActivityModule.class)
    public interface ActivityComponent {
        Activity activity();
    
        void inject(LoginActivity loginActivity);
    
        void inject(MainActivity mainActivity);
    
        // ....
    }
    

    ActivityModule:注入Activity,同时规定Activity所对应的域是@ActivityScope

    @Module
    public class ActivityModule {
        private final Activity activity;
    
        public ActivityModule(Activity activity) {
            this.activity = activity;
        }
    
        @Provides
        @ActivityScope
        Activity activity() {
            return this.activity;
        }
    }
    

    至此,注入工作初步完毕了,看到这里,可能有童鞋有疑问,Presenter(或者Biz)的注入在哪里,为何没在ActivityComponent里?
    是的,正常来说,结构图应该是下面这张图的样子:


    我建议使用这种方式,对于不同的Activity,创建各个对应的ActivityCompontent,同时把Presenter(Biz)注入到Component的视图中,这也是dagger2推荐的做法,Dagger 2希望使用@Component注解接口将依赖关系链接起来。

    而我的做法没有把Presenter注入到ActivityComponent中,因为Presenter的作用域和Activity一样,好处是节省代码(- -),大家可以根据项目情况自行选择注入方式。

    使用:

    public class LoginActivity extends BaseActivity implements LoginView, ValidCodeView {
        @Inject LoginPresenter loginPresenter;
    
        @Inject ValidCodePresenter validCodePresenter;
    
       @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_login);
    
            initInject();
            // 此处省略N行代码
        }
    
        private void initInject() {
            // 构建Component并注入
            getActivityComponent().inject(this);
            loginPresenter.attachView(this);
            validCodePresenter.attachView(this);
        }
    
        //  建议写在基类Activity里
        protect ActivityComponent getActivityComponent(){
              return  DaggerActivityComponent.builder()
                          .appComponent(getAppComponent())
                          .activityModule(getActivityModule())
                          .build();
        }
    
        //  建议写在基类Activity里
        protect ActivityModule getActivityModule(){
              return new ActivityModule(this);
        }
    
        // 建议写在MyApplication类里
        public AppComponent getAppComponent(){
             return DaggerAppComponent.builder()
             .appModule(new AppModule((MyApplication)getApplicationContext()))
             .build();
        }
    }
    

    其中LoginPresenter:

    @ActivityScope
    public class LoginPresenter extends DefaultMvpPresenter<LoginView, RESTResult<UserVO>> {
         // 此处省略
    
        @Inject
        public LoginPresenter(ApiService apiService, ThreadExecutor jobExecutor, SpfManager spfManager) {
            this.apiService = apiService;
            this.jobExecutor = jobExecutor;
            this.spfManager = spfManager;
        }
        public void login(String mobile, String code) {
              // todo
        }
    }
    

    这样,dagger2的简单使用就介绍完毕了,如果有对一些基础概念不是很理解的童鞋,可以查看官方文档

    相关文章

      网友评论

      • 629d3e4ca122:为什么我make project 时 报错:
        android.app.Application cannot be provided without an @Inject constructor or from an @Provides-annotated method.
        android.app.Application is injected at
        com......di.module.ClientModule.provideClient(application, …)
      • 小小程序员jh:加1,学习下。
      • 戴定康:后面两段晦涩难懂
      • boboyuwu:请教下楼主哈 为啥构造方法上面可以用Inject不能用Qualifier?
      • wowling:感谢感谢!
      • woniu0936:请问下面代码中,写的这些方法的作用是什么?在AppModule中已经写了他们的provide方法,在使用@inject标记一个对象时,会自己去appModule中找需要的东西,为什么还要在AppComponent在申明一遍这些方法?不声明这些方法,也能找到提供的这些对象啊:
        @singleton
        @Component(modules = AppModule.class)
        public interface AppComponent {
        Context context(); // 提供Applicaiton的Context

        ThreadExecutor threadExecutor(); // 线程池

        ApiService apiService(); // 所有Api请求的管理类

        SpfManager spfManager(); // SharedPreference管理类

        DBManager dbManager(); // 数据库管理类
        }
        YoKey:@woniu0936 更直观,更优雅,类似一个全局定义的桥梁声明类,这样在业务复杂的时候,component依然简洁,它负责暴露可注入的对象
        woniu0936:@YoKey 除过因为dagger推荐声明注入外,声明注入比不声明注入有什么好处或者说是不同呢?
        YoKey:@woniu0936 dagger推荐使用component来声明注入,不注入当然也是可以直接使用的~
      • bhfo:请问@ActivityScope,这个注解具体是怎样运作的?怎么加上这个就可以与Activity的生命周期绑定了?
        bhfo:@sunshine8 算懂了,实际还是由注射器来管理生命期的。
        信念着了火:@bhfo 你现在有答案吗?我也不清楚
      • AhaCat:大神能不能推荐一下氛围比较好的安卓论坛或者网站啊? :blush:
        YoKey: @AhaCat 简书~gankio~掘金…等等
      • yangyirunning:路过就顶,貌似现在用注解的越来越多了,得空研究一下 :heart_eyes:
      • fef3a2360375:https://github.com/CarlLu/MVPframe
        mvp+rxjava+retrofit+dagger2开源框架,希望大家支持
      • Android解忧杂货店:兄弟,能不能贴个github地址,研究一下代码mvp结构。。
        YoKey:@beyond小哥 这篇是我实际项目中的一些代码片段;推荐你一个项目,可以参考下https://github.com/CycloneAxe/phphub-android;dagger2注入方式有多种方式,最终都可以达到同样的目的;
        至于MVP,我建议从最基本的MVP入手,然后参考些mosby、nucleus之类的MVP封装项目进一步改造自己的MVP架构 :smile:
        Android解忧杂货店:@YoKey 嗯嗯,了解。那这篇文章的Demo还有吗?我刚刚开始学习使用Dagger2,准备用在项目中。有的话给个链接下载看看,或是发我邮箱:859358014@qq.com,万分感谢!
        YoKey:@beyond小哥 :) 地址就在我的简书主页介绍上~ 我的github上还没有MVP相关的DEMO,等以后有机会会分享的~ :joy:
      • HelloVass:今天又看了一遍,我很好奇,导致循环引用错误的原因是什么,右右能贴一下代码吗?
        YoKey:@HelloVass provideDbManager(xx)方法提供了一个Dbmanager对象,但是确依赖了自己(DbManager dbManager) 这样在编译时会报Dependency cycle错误
      • HelloVass:看了前面半段还以为右右要讲架构设计了,戛然而止,白开心了
        v3sona:@LCN 参考google 的 mvp dagger 写了个demo
        里面还用了retrofit2,okhttp3,RxJava,RxAndroid,ButterKnife等
        https://github.com/vsona/orz
        LCN:@YoKeyword 楼主可不可以贴个demo之类的参考下
        YoKey:@HelloVass 思路说了下啦 可以试试 目前经过了几次重构 感觉还行 有了Rx业务逻辑的处理和维护很爽 安卓里绝大多数情况没有特别复杂的业务逻辑 把M和P轻薄处理 感觉能满足我目前接触到的项目开发需求

      本文标题:Dagger2使用

      本文链接:https://www.haomeiwen.com/subject/inbrhttx.html