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. 在android系统上写C语言程序--开机启动该程序不进入安卓系统

    今天要写的这篇博文意义重大,也是网上很少有的,这是在我工作中学会的一项技术,当然,它也是由简单的问题组合而来的.如何在安卓中写C语言程序,调试安卓驱动,测试程序的的一项重要技能,下面我就不说废话了,直 ...

  2. Android新特性Instant Run详解

    关于 Instant Run Android Studio 2.0 中引入的 Instant Run 是 Run 和 Debug 命令的行为,可以大幅缩短应用更新的时间.尽管首次构建可能需要花费较长的 ...

  3. ROS机器人程序设计(原书第2版)学习镜像分享及使用说明

    ROS机器人程序设计(原书第2版)学习镜像分享及使用说明 系统用于ROS爱好者学习交流,也可用于其他用途,并不局限于ROS. 这款镜像文件是基于一年前的Ubuntu ROS Arduino Gazeb ...

  4. REFRESH删除POSTGRESQL

    sudo apt-get install python-psycopg2sudo apt-get install postgresql sudo su - postgres createuser -- ...

  5. Dynamics CRM2013 Form利用window.location.reload()进行全局刷新带来的问题及解决办法

    CRM2013以后,表单的保存后变成了局部刷新而非全局刷新,但很多情况下我们需要刷新整个页面,通过刷新页面来使脚本执行或者业务规则执行来实现某些业务效果,一般我们会使用window.location. ...

  6. Erlang的常驻模块与功能模块

    Erlang的常驻模块与功能模块Residence moduleThe module where a process has its tail-recursive loop function(s).I ...

  7. ViewPager 几个状态详解

    ViewPager.SCROLL_STATE_DRAGGING 当用户按下ViewPager视图并且需要滑动第一下时; ViewPager.SCROLL_STATE_SETTLING: 当用户滑动的放 ...

  8. JVM的GC(概念与深入)

    深入浅出了解什么是GC: http://my.oschina.net/xianggao/blog/86985 GC策略详解: http://blog.csdn.net/winniepu/article ...

  9. 【ShaderToy】基础篇之谈谈点、线的绘制

    写在前面 写前面一篇的时候,发现还是不够基础.因此打算增加几篇基础篇,从点线面开始,希望可以更好理解. 其实用Pixel Shader的过程很像在纸上绘画的过程.屏幕上的每一个像素对应了纸上的一个方格 ...

  10. Cocos2D结合CoreGraphics实现RPG人物中空黑洞吸入效果

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 之前的博文中我们实现了RPG人物的复古效果. 现在我们再完点h ...