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

文/YoKey(简书作者)

原文链接:http://www.jianshu.com/p/c2feb21064bb

著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
												

Android 之dragger使用的更多相关文章

  1. android UI库

    https://github.com/wasabeef/awesome-android-ui List of Android UI/UX Libraries A curated list of awe ...

  2. Android中GridView拖拽的效果【android进化三十六】

      最 近看到联想,摩托罗拉等,手机launcher中有个效果,进入mainmenu后,里面的应用程序的图标可以拖来拖去,所以我也参照网上给的代码,写了 一个例子.还是很有趣的,实现的流畅度没有人家的 ...

  3. Android 一步一步教你使用ViewDragHelper

    在自定义viewgroup的时候 要重写onInterceptTouchEvent和onTouchEvent 这2个方法 是非常麻烦的事情,好在谷歌后来 推出了ViewDragHelper这个类.可以 ...

  4. Android好用且常用的插件及工具

    1.GitHub,这个不管是做安卓还是其他,只要是开发就必上的网站,也是天朝没有墙掉为数不多的网站 2.Stack OverFlow,这个和上面一样,国外非常著名的问答网站,在上面基本上很多问题都可以 ...

  5. Android中GridView拖拽的效果

    最 近看到联想,摩托罗拉等,手机launcher中有个效果,进入mainmenu后,里面的应用程序的图标可以拖来拖去,所以我也参照网上给的代码,写了 一个例子.还是很有趣的,实现的流畅度没有人家的那么 ...

  6. android ListView和GridView拖拽移位具体实现及拓展

    关于ListView拖拽移动位置,想必大家并不陌生,比较不错的软件都用到如此功能了.如:搜狐,网易,百度等,但是相比来说还是百度的用户体验较好,不偏心了,下面看几个示例:              首 ...

  7. Dragger代码实现

    转自:http://www.apkbus.com/blog-705730-60436.html 在工程中引入Dagger 如果想使用Dagger的话,需要添加两个函数库: dependencies { ...

  8. android ListView和GridView拖拽移位实现代码

    关于ListView拖拽移动位置,想必大家并不陌生,比较不错的软件都用到如此功能了.如:搜狐,网易,百度等,但是相比来说还是百度的用户体验较好,不偏心了,下面看几个示例:             首先 ...

  9. Android Annotations(2)

    AndroidAnnotations是一个开源框架,旨在加快Android开发的效率.通过使用它开放出来的注解api,你几乎可以使用在任何地方, 大大的减少了无关痛痒的代码量,让开发者能够抽身其外,有 ...

随机推荐

  1. Xcode Organizational Identifiers

    操作系统(不管是iOS或是OS X)使用bundle标识去唯一标识你的应用.Bundle标识由一个组织id和你App的名字组成. 一般的,组织id是你域名的反转.如果你的域名是example.com那 ...

  2. sklearn:最近邻搜索sklearn.neighbors

    http://blog.csdn.net/pipisorry/article/details/53156836 ball tree k-d tree也有问题[最近邻查找算法kd-tree].矩形并不是 ...

  3. Tomcat怎么实现异步Servlet

    有时Servlet在生成响应报文前必须等待某些耗时的操作,比如在等待一个可用的JDBC连接或等待一个远程Web服务的响应.对于这种情况servlet规范中定义了异步处理方式,由于Servlet中等待阻 ...

  4. xlsx批量转为utf8的csv

    xlsx批量转为utf8的csv(金庆的专栏)策划的配置表为 xlsx 表格,可以有注释,公式.服务器和客户端使用的配置文件需要转成 csv 文件.使用 WPS 另存无法批量转换,并且结果不是utf8 ...

  5. Java提升篇之反射的原理

    Java提升篇之反射的原理 1.构造方法的反射 import java.lang.reflect.Constructor; public class ReflectConstructor { publ ...

  6. 1.0、Android Studio管理你的项目

    项目概览 Android Studio中的项目包含了开发一个app的工作环境所需要的一切.从代码,到资源,到测试到构建配置.当你创建一个新的项目的时候,Android Studio为所有的文件创建了必 ...

  7. Servlet之文件上传

    上传表单中的注意事项: 表单 method 属性应该设置为 POST 方法,不能使用 GET 方法 表单 enctype 属性应该设置为multipart/form-data 下面的实例是借助于com ...

  8. Windows平台下的多线程编程

    线程是进程的一条执行路径,它包含独立的堆栈和CPU寄存器状态,每个线程共享所有的进程资源,包括打开的文件.信号标识及动态分配的内存等.一个进程内的所有线程使用同一个地址空间,而这些线程的执行由系统调度 ...

  9. 01_MyBatis EHCache集成及所需jar包,ehcache.xml配置文件参数配置及mapper中的参数配置

     1 与mybatis集成时需要的jar ehcache-core-2.6.5.jar mybatis-ehcache-1.0.2.jar Mybatis.日志.EHCache所需要的jar包如下 ...

  10. 利用cocos2d-x实现CandyCrushSaga消除功能

    猴子原创,欢迎转载.转载请注明: 转载自Cocos2D开发网–Cocos2Dev.com,谢谢! 原文地址: http://www.cocos2dev.com/?p=455 昨天没事写了个三消玩玩.已 ...