Dagger2使用

ylwh9632 8年前

来自: http://www.jianshu.com/p/c2feb21064bb


在简单使用了一段时间的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可以通过自定义注解限定注解作用域,一般在Module里规定scope的生命周期,比如下面的ActivityScope在ActivityModule里绑定。

@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的简单使用就介绍完毕了,如果有对一些基础概念不是很理解的童鞋,可以查看官方文档