Android 之dragger使用

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java呓语

Tips·检测应用程序被卸载

我们知道广播ACTION_PACKAGE_REMOVED可以监听应用程序卸载,但不幸的是这个意图被卸载的程序是不可知的,所以无法监听到自己的程序被卸载。

1263
来自专栏青蛙要fly的专栏

超详细的生命周期图-你能回答全吗

超详细的Activity与Fragment的生命周期图,可能大家会说你这篇文章也太水了吧。就这么一个破图。可是我觉得它写的很详细,有些方法是哪些情况下会运行,哪...

1052
来自专栏做全栈攻城狮

安卓开发基础教程-Android多界面应用程序开发

本套教程主要讲解安卓开发的相关知识,从基础到精通。一方面可以巩固自己所得,另一方面可以帮助对安卓开发感兴趣的朋友。

1174
来自专栏Android先生

(新瓶旧酒)谷歌官方MVP项目学习--浅入源码

项目的目的是通过展示各种架构app的不同方式来帮助开发者解决架构问题。项目中通过不同的架构概念及方式实现了功能相同的app。你可以用示例来当做参考,或是干脆拿来...

1071
来自专栏ASP.NET MVC5 后台权限管理系统

.Net 转战 Android 4.4 日常笔记(4)--按钮事件和国际化

我们知道资源被注册到R.java我们通过R.java就可以读取到界面中的组件。跟我们.net一样,通过ID来读取组件 知识点: 通过R.java读取组件 Mai...

1925
来自专栏Android开发指南

14.极光推送

41611
来自专栏pangguoming

Android 使用dagger2进行依赖注入(基础篇)

0. 前言 Dagger2是首个使用生成代码实现完整依赖注入的框架,极大减少了使用者的编码负担, 本文主要介绍如何使用dagger2进行依赖注入。如果你不还不了...

4257
来自专栏Android机器圈

Retrofit网络请求库应用01

PS:什么是Retrofit?   在官方文档中有这样一句话--A type-safe HTTP client for Android and Java(一个类...

3208
来自专栏编程思想之路

Android中应用调用系统权限

现在设备的安全性越来越受到重视,随之而来的便是开发中的各种不便,比如有普通权限,运行时权限,系统权限之分。对于运行时权限的添加可以参考 对于Android中各个...

2816
来自专栏技术小黑屋

Android处理崩溃的一些实践

对于任何程序来说,崩溃都是一件很难避免的事情,当然Android程序也不例外。在Android程序中,引起崩溃的多属于运行时异常或者错误,对于这些异常我们很难做...

1232

扫码关注云+社区

领取腾讯云代金券