当 Dagger2 应用在 MVP 框架中

原文链接:当 Dagger2 应用在 MVP 框架中

关于 Dagger2 自己一只想搞明白,但是从去年开始到现在,说真的,看过不少介绍 Dagger2 的文章,但自己一只云里雾里,最近打算把 Dagger2 应用到 MVP 框架中去,所以就重新翻看相关技术文章,重新学习下,下面算是自己这两天学习 Dagger2 后对 Dagger2 的认识,不一定都正确,如果 错误,欢迎指正,只要从代码角度出发,认识 Dagger2。

Note:如果你对 MVP 和 Retrofit 都不熟悉,这篇文章可能不适合你阅读。

学习初衷

前段时间按照 MVP 架构重构过一个妹子客户端GankDaily ,关于 MVP 具体在 GankDaily 中如何使用,自己也专门写过一篇文章介绍过, MVP 模式在 GankDaily 中的应用 ,如果看过 GankDaily 的代码,其实不仅仅是 GankDaily 这个项目,所有 使用 MVP 架构的项目,都会存在一个问题,那就是每个 Activity 中一定会有一个 Presenter 实例对象,如下所示

/**
  * the presenter of this Activity
  */
 private MainActivityPresenter mPresenter;

它是 Activity 的控制器,所有的数据请求、界面更新都直接或间接的被它控制。然后每个Activity 都需要在 onCreate 中 去实例化它,如下所示

mPresenter = new MainActivityPresenter(this, user);

上面看上去没什么不妥,但是如果你听过依赖注入(关于依赖注入,这里一哥们写的文章介绍的不错, 依赖注入原理),就知道这种使用 new 关键字去实例化一个对象有诸多不好的地方, 这种 new 实例的方式 其实是一种硬编码。为什么?

试想一下,如果以后 MainActivityPresenter 的构造方法中的参数发生变化,那么此时,不仅仅在 MainActivityPresenter 类中改动了 MainActivityPresenter 的构造器相关的代码,你还需要在所有使用到 MainActivityPresenter 的地方修改代码,这不就是硬编码吗?

那你肯定想问? “你说说除了这样的方法,还有什么方法能避免你上面说的这种问题呢?”

答案就是今天的主题 – Dagger2

试想一下,如果把 MainActivityPresenter 实例的获取,事先通过一个辅助类约定好,那么具体使用的时候,通过辅助类 去生成 MainActivityPresenter 的对象,那么是不是会好点,其实这个辅助类,在我理解而来就是 Dagger2 中的 Module 概念。

当然 Dagger2 除了可以解决硬编码的问题,还有其他很多好处,如方便测试等等。

以上算是自己学习的初衷,总结一下,我使用 Dagger2 的愿景或者最终的预期的结果就是 在Activity 中看不到 new Presenter() 这样的代码,直接在 定义 Presenter 实例时,用 @Inject 注解一下,Presenter 的实例就生成。

最终结果

下面自己将会使用 Dagger2 + MVP架构模式 + Retrofit 演示一个简单的 demo 。

这个demo 只有一个 MainActivity界面,最终的效果是在 MainActivity 通过 MainActivityPresenter 获取到一个 字符串显示在 MainActivity 。

这里关于 Dagger2 和 MVP 你应该已经了解他们为什么存在,但是对于 Retrofit 可能有点疑惑,关于 Retrofit:

Retrofit:用来模拟一般的网络数据获取,这个目前大家用的比较多,也确实是一个很方便的库,加上支持 RxJava ,它用于获取数据真是极方便的。 既然要用 Retrofit ,就应该知道整个应用中,最好只存在一个 Retrofit 实例。

环境配置

根目录的 build 文件加入 android-apt 支持

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath ‘com.android.tools.build:gradle:1.1.0‘
        classpath ‘com.neenbedankt.gradle.plugins:android-apt:1.4‘
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

在 app 目录的 build 文件中加入 apt plugin 的支持

apply plugin: ‘com.neenbedankt.android-apt‘

加入 Dagger2 retrofit OkHttp 依赖

//dagger2
compile ‘com.google.dagger:dagger:2.0‘
apt ‘com.google.dagger:dagger-compiler:2.0‘
provided ‘org.glassfish:javax.annotation:10.0-b28‘

//Square
compile ‘com.jakewharton:butterknife:6.1.0‘
compile ‘com.squareup.retrofit:retrofit:1.9.0‘
compile ‘com.squareup.okhttp:okhttp:2.3.0‘

在 Application 中实践 Dagger2

现在依赖都已经加入,开始动手使用 Dagger2 ,第一步考虑我们的 Application。

先创建 AppApplication,并在 AndroidMainfest.xml 注册好。

public class AppApplication extends Application{

        @Override
        public void onCreate() {
            super.onCreate();
        }
}
<application
       android:name=".AppApplication"
       android:allowBackup="true"
       android:icon="@mipmap/ic_launcher"
       android:label="@string/app_name"
       android:theme="@style/AppTheme" >

</application>

这里想想,在 Application 中应该做点什么呢?Application中一般可以做一些全局性相关的事。

对于 Retrofit ,前面也说了应该在全局中只存在一个实例,所以 Application 中可以有一个全局性的 Retrofit。

说到这里,感觉说的有点费劲,主要是自己理解的也还不够深入,先这样吧,反正是写给自己以后看的,如果对你,正在读文章的你造成了 困惑,还请见谅。如果读文章有点费劲,建议直接看已经存在于Github上最终的源代码

基于上面的分析, Application 可能需要一个依赖,依赖于 ApiServiceModule(提供 Retrofit 实例), 这里我们看看 ApiServiceModule 的代码实现

@Module
public class ApiServiceModule {
    private static final String ENDPOINT="";

    @Provides
    @Singleton
    OkHttpClient provideOkHttpClient() {
        OkHttpClient okHttpClient = new OkHttpClient();
        okHttpClient.setConnectTimeout(60 * 1000, TimeUnit.MILLISECONDS);
        okHttpClient.setReadTimeout(60 * 1000, TimeUnit.MILLISECONDS);
        return okHttpClient;
    }

    @Provides
    @Singleton
    RestAdapter provideRestAdapter(Application application, OkHttpClient okHttpClient) {
        RestAdapter.Builder builder = new RestAdapter.Builder();
        builder.setClient(new OkClient(okHttpClient))
                .setEndpoint(ENDPOINT);
        return builder.build();
    }

    @Provides
    @Singleton
    ApiService provideApiService(RestAdapter restAdapter) {
        return restAdapter.create(ApiService.class);
    }
}

任何 Module 类的开头都以 @Module 进行注解。

然后,最终 ApiServiceModule 需要提供给 AppApplication ,这里不能直接将 ApiServiceModule 给 AppApplication , 现在需要一个组件对他进行整合 这个组件我们对他命名为 AppComponent下面是它的实现。

@Singleton
// 如果这里有多个 可以用逗号隔开,继续追加
@Component(modules = {ApiServiceModule.class})

public interface AppComponent {

    ApiService getService();

}

这里你会看到他是一个接口,然后在类申明的开始的位置,用 @Component 指定了他具体的依赖的类。

这个接口只有一个方法,返回了之前设想的一个全局实例 ApiService。

既然是接口,那么一定有类去实现他,设想一下,如果有一个类实现了上面的接口, 我们只要在 AppApplication 中得到 这个实现的对象,那这个对象不就是 AppComponent,然后我们不就 通过 AppComponent 获取到实例对象了吗?恩~ 就应该是这样。

现在定义好 AppComponent 接口,然后经过编译,当你在编辑器 打出 Dagger 编辑器就会自动提示 DaggerAppComponent 这个类。

恩?这是怎么回事?

这其实是 Dagger2 帮你自动生成的。

现在在 AppApplication 中直接使用 DaggerAppComponent,用它来得到 AppComponent 对象,然后有了 AppComponent 那么 ApiService 不就随之而来了吗?

AppApplication 中代码现在如下所示

public class AppApplication  extends Application{

    public static AppApplication get(Context context){
       return (AppApplication)context.getApplicationContext();
    }

    private AppComponent appComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        appComponent=DaggerAppComponent.builder()
                .apiServiceModule(new ApiServiceModule())
                .build();
   }

    public AppComponent getAppComponent() {
        return appComponent;
    }
}

那么现在只要在任何地方想要获取 ApiService 的实例,只要得到了 AppApplication 的实例(AppApplication.get(), 就可以通过 AppAppLication 的 getAppComponent() 方法得到 AppComponent ,然后通过 AppComponent 就可以间接得到 ApiService 的实例了。

上面大概说了下在 Application 中应用 Dagger2 去实例化 AppComponent,其实在 Activity 使用也是同样的道理。现在暂时没时间 写在 Activity 中怎么使用 Dagger2 了,具体可以从代码中查看。

代码都已经在 Github ,欢迎查阅

时间: 2024-08-02 09:46:14

当 Dagger2 应用在 MVP 框架中的相关文章

MVP框架设计详解

MVP MVP简介 Model View Presenter ActivityView MVP各层关系梳理 ?? Model与Presenter ?? View与Presenter ?? Presenter完成的交互 ?? Model与View之间的交互 MVP适用环境 MVPRetrofitRxJava 加入Retrofit 创建interface 修改Model层内容 修改Presenter层内容 加入RxJava 修改Interface 修改Model层 修改Presenter层 总结 M

简单的MVP框架搭建

1.MVP框架介绍: 最近公司内部培训,正好理一下项目的架构,目前最主要的产品还是用的MVP软件设计模式,就顺便查查资料来做个总结. 1.1什么是MVP? MVP是Model-View—Presenter的缩写,从网上找到的资料来看,大多数时候,对于MVP的介绍还是基于MVC,关注点基本上就集中在Presenter上面了,wiki上有个简单的说明(MVP模式),先从定义来大概理解下这个模式: 1.2MVP各自的使用规则和相互的交互 这三个模块,一般情况下,对于view的理解是没什么争议的,就是界

mvp框架

本文在于巩固基础 mvp框架的概念: MVP是MVC模式的另一个变种,MVP即可以应用到WEB项目中, 也可以应用到Winform项目中,它的方便的测试机制为大型复杂的企业级应用带来了福音,MVP模式的层次图. 从图中可知道,MVP有Model-Presenter-View三个层次,下面是时序图 Controller层是负责状态保存和页面流转的有时根据需要,也需要Controller的参与 由以上几幅图综合分析可知,Presenter相当于中介者的作用,它负责接收视图发送来的请求,调用Model

Retrofit源码分析以及MVP框架封装使用

阅读此文前请先阅读Retrofit+okhttp网络框架介绍 从上文中我们已经了解通过如下代码即可得到返回给我们call 以及 response对象,今天我们通过源码来分析这个过程是如何实现的. /** * 获取天气数据 * @param cityname * @param key * @return */ @GET("/weather/index") Call<WeatherData> getWeatherData(@Query("format") S

Android MVP框架MVPro的使用和源码分析

最近看了两篇关于Android实现MVP的文章一种在android中实现MVP模式的新思路和用MVP架构开发Android应用. 两篇文章的思路都是一样的,即把Activity.Fragment作为Presenter,这种方式不同于现在主流的MVP方式,不过它很好的解决了Activity生命周期带来的问题,而且我认为它让MVP的实现更加轻松了. 那么问题来了,这么好的思路,我们怎么可以不去实现一下自己的MVP呢? 于是我花了一晚上的时候整出了一个小小的MVP框架--MVPro MVPro介绍 M

android课程表控件、悬浮窗、Todo应用、MVP框架、Kotlin完整项目源码

Android精选源码 Android游戏2048 MVP Kotlin项目(RxJava+Rerotfit+OkHttp+Glide) Android基于自定义Span的富文本编辑器 android课程表控件效果源码 Dagger.Clean.MVP框架搭建,快速开发- Andorid 任意界面悬浮窗,实现悬浮窗如此简单 android模仿QQ登录后保存账号和密码效果源码 Android简洁清爽的Todo清单工具(MVP+okhttp3+retrofit+gson) Android优质博客 K

MyBatis框架中Mapper映射配置的使用及原理解析(七) MapperProxy,MapperProxyFactory

从上文<MyBatis框架中Mapper映射配置的使用及原理解析(六) MapperRegistry> 中我们知道DefaultSqlSession的getMapper方法,最后是通过MapperRegistry对象获得Mapper实例: public <T> T getMapper(Class<T> type, SqlSession sqlSession) { final MapperProxyFactory<T> mapperProxyFactory =

OC学习篇之---Foundation框架中的其他类(NSNumber,NSDate,NSExcetion)

1.NSNumber 这个类主要是用来封装基本类型的,说到这里,就不得不说一下了: OC中的集合是不允许存入基本类型的,所以NSNumber类就诞生了,需要将基本类型封装一下,然后存进去,这个类似于Java中的自动装箱和拆箱,Java中的集合其实也是不允许存入基本类型的,但是我们任然看可以那么操作,就是因为有自动装箱功能,如果你将Eclipse的JDK改成5.0之前的,你看看还能操作吗.. 注:那为什么基本类型不能存入到集合中呢? 原因是在操作集合的时候会操作集合元素中的方法,但是基本类型是没有

MVC框架中的值提供(一)

在MVC框架中action方法中的Model数据的绑定的来源有很多个,可能是http请求中的get参数或是post提交的表单数据,会是json字符串或是路径中的相关数据;MVC框架中针对这些不同的数据来源抽象了IValueProvider接口; public interface IValueProvider { bool ContainsPrefix(string prefix); ValueProviderResult GetValue(string key); } IValueProvide