2017安卓主流框架搭建?看这篇就够了(下)

四.mvp模式(使用MVPPluge插件,自动生成MVP的类文件以及该插件的改装)

MVP模式理解起来很容易,结合安卓,简单概括:无非就是在activty中将网络请求等与数据相关的操作封装到一个P类中,activty中持有P的引用,同时P中又包含activty中调度View的一些方法,这样activity中只写业务逻辑,请求获取数据全靠P去实现,好处是在请求很多,业务逻辑复杂的情况下整个activity的代码依然清晰,同时activity的职责也更单一。

曾经看到过一句话,大致的意思是:

"代码的规范,业务逻辑的清晰,类之间的解耦等等一定是通过增加而不是减少代码来实现的。”

同样,mvp的问题也就暴露出来了,要实现activity中模块的分离,需要增加P类,需要实现各种接口,因此,之前的项目中一直未使用mvp,都是在activity中写到底,最多就是抽取一些方法到util,helper等类中。
这回虽然引入了mvp,但是实际方法中同样也是分情况来看,如果要实现的功能很简单,或者功能很边缘化,甚至小迭代时间紧,任务重的时候还是直接activity中操作数据,只有在一些比较重要,核心的模块里 通过mvp来做更优雅的实现。
题外话到此,下面重点来说说这次项目搭建中mvp的使用过程。

使用过程:

1.android studio引用 MVPPlugin插件
2.MVPPlugin插件的使用
3.MVPPlugin插件的改造

可以看到这里mvp模式都是围绕一个“ MVPPlugin插件”的东西,这个插件是干嘛的? 其实就是一个帮助开发者一键生成mvp模式所需要的一些接口类,P类等。具体的使用方法可以看看这个

http://mp.weixin.qq.com/s/fo34hyvjzNSURSh_V8y4oQ

如果你之前也只是听说并未真正使用过mvp模式开发,那么这个插件将极大的节约你的mvp上手的时间成本,基本属于拿来就用。 不过用归用,插件帮你生成的那些类的源码还是要好好看看,特别是基类,做到消化吸收!可能自己暂时写不出来,但起码要理解原理。

五.网络框架的接入(RXJava2+Retrofit2.0+OKHTTP)

这三个玩意儿无疑是目前灰常火的项目,但凡做android开发,可以说不一定用过,但绝对都听过,了解过。

Rxjava:

是个很神奇的东西。网上的描述一大堆:什么 事件流推动,响应式编程,观察订阅等等 我刚接触的时候百度了半天,也没弄清楚到底是个啥,使用有啥好处,直到看到这篇文章,
我将作者称为“管神”,水管的管。

http://www.jianshu.com/u/c50b715ccaeb([给初学者的RxJava2.0教程)

哈哈 有一个系列,帮助上手Rxjava,但实际上你可能会跟我一样。 系列文章看了一遍,感觉懂了,但是想在项目里面用,发现用不上。
然后结合Retrofit2.0+OKHTTP直接先在项目里面用起来,用熟练了再把文章看一遍,哦,恍然大悟-事件推动。
说得好像有点云里雾里,先别喷我,咋先用上再说。

Retrofit2.0:

是个很方便的东西,说它方便,是因为它像一个接口,本身没有实现,没有功能,但是你把Gson框架放进去,它就能json解析,你把OKHTTP放进去它就能发送网络请求,你把Rxjava放进去它就能进行发送事件流。
那么整个的连接起来是神马?
RXJava2+Retrofit2.0+OKHTTP+GSON=“发送 网络请求 并自动解析json数据的事件流”
可能你会说了,作者你又装X,神马框架不能发送网络请求,然后解析json数据?
但我会告诉你,这个X我装定了!重点是“事件流”三个字。现在你给我0分,等你把上面推荐的rxjava文章看完理解之后或许你会重新打出97分。
为了增加说服力,这里我给出一个复杂的场景:

同时压缩两张图片,都压缩成功后调用上传接口,并将上传接口返回的部分数据作为参数,请求另外一个接口。

这个需求涉及的东西还不少,图片压缩,线程变换,网络请求嵌套。如果不用rxjava,可能最常规的方法应该是这样:
开两个子线程压缩图片,handler发送成功信号到主线程,while循环等待,两个标识都成功然后发送网络请求,请求成功回调再嵌套一个请求。
上面的实现基本上能满足这个需求,但是无论从代码量,代码可读性等等而言都不是那么优雅,但是如果采用rxjava,利用它自带的线程切换,操作符zip,事件流转换flatMap的话,你可以写出一段逻辑清晰,代码量少的链式代码,,,,,
好吧,可能这样描述无法达到那种 “听到后连我自己都害怕”的效果,,但是,请相信,,效果真的很牛X,谁用谁知道。

基本使用:

1.初始化一个OkHttpClient

  OkHttpClient  mOkHttpClient = new OkHttpClient.Builder()
            .readTimeout(DEFAULT_READ_TIMEOUT_MILLIS, TimeUnit.SECONDS)
            .writeTimeout(DEFAULT_WRITE_TIMEOUT_MILLIS, TimeUnit.SECONDS)
            //设置连接超时时间
            .connectTimeout(DEFAULT_CONNECT_TIMEOUT_MILLIS, TimeUnit.SECONDS)
            //设置缓存
            .cache(getDefaultCache())
            //日志拦截器
            .addInterceptor(loggingInterceptor)
            //头部拦截器
            .addInterceptor(new HeadsInterceptor())
            //设置SSH 兼容https
            .sslSocketFactory(sslSocketFactory.sSLSocketFactory, sslSocketFactory.trustManager)
            //默认全部信任
            .hostnameVerifier(SSHUtil.getHostnameVerifier())
            .build();

2.通过Retrofit.Builder初始化一个RetrofitApi对象,过程中设置请求代理(就是前面mOkHttpClient ),设置数据解析,设置Rxjaxa

 Retrofit.Builder builder = new Retrofit.Builder()
            //设置网络请求实现
            .client(mOkHttpClient)
            //设置json数据解析实现
            .addConverterFactory(GsonConverterFactory.create())
            //RXJAVA适配器
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create());

    //这里主域名的设置单独来弄,万一后台奇葩,一个app里两个主域名的话可以再建一个API_X的接口类,这里类似的单独再配置他的baseurl
   RetrofitApi  httpApi = builder.baseUrl(Constants.APP_HOST)
            .build()
            .create(RetrofitApi.class);

    //配置了RxJava2CallAdapterFactory即集合RXjava的话httpApi调用xxx方法可以直接返回Observable,然后拿来subscribe
    //不结合RXjava的话返回httpApi调用xxx方法返回Call对象,然后拿来enqueue发请求

    //结合RXjava的优点:更灵活,链式调用,线程切换方便,各种操作符效果吊炸天。 说白了就是可以在处理很复杂嵌套循环请求的时候利用RXJAVA,简化开发
    //不过RXJAVA自身的学习成本的确是个问题,我到现在也是云里雾里,不过既然是框架,,,先用再说啦!

3.调用RetrofitApi实例里的业务接口并处理回调

  httpApi.getIndexData().subscribe(new Observer<TDataBean<IndexMultBean>>() {
        @Override
        public void onSubscribe(Disposable d) {
            
        }

        @Override
        public void onNext(TDataBean<IndexMultBean> value) {

        }

        @Override
        public void onError(Throwable e) {

        }

        @Override
        public void onComplete() {

        }
    })
全局封装说明:

真正使用过程中肯定不会每次请求都重复上面过程,都会做封装,这里是给出的封装实例,可能并不完美,欢迎批评指出哈!

三个类,分别是:
HttpUtil:初始化retrofit,并根据服务器主域名生成一个全局的 RetrofitApi对象
RetrofitApi: 注解的方式定义出具体的业务接口
ApiManager:网络请求发起类,通过获取HttpUtil中的retrofit实例,调用retrofit中定义的业务接口并传入参数。

在MVP模式的Presenter 里调用方式如下:

public class LoginPresenter extends BasePresenterImpl<LoginContract.View> implements LoginContract.Presenter {
private void textHttp() {
    ApiManager.login("acount","pwdString").subscribe(new HttpObserver<TDataBean<UserInfo>>(mView) {
        @Override
        public void onSucceed(TDataBean<UserInfo> value) {

        }

        @Override
        public void onDefeat(TDataBean<UserInfo> value) {
            super.onDefeat(value);
        }
    });
}

}

HttpObserver继承自Observer<T>,对请求结果做了进一步的封装,具体见源码

部分源码展示:

1.添加引用依赖

 //OKhttp
compile 'com.squareup.okhttp3:okhttp:3.9.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.7.0'
 //retrofit
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
compile 'com.squareup.retrofit2:converter-gson:2.2.0'
//rxjava
compile 'io.reactivex.rxjava2:rxjava:2.0.1'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'

2.请求模块初始化

public class HttpUtil {
//超时时间
private static final long DEFAULT_READ_TIMEOUT_MILLIS = 20;//提交数据超时时间
private static final long DEFAULT_WRITE_TIMEOUT_MILLIS = 20;//提交数据超时时间
private static final long DEFAULT_CONNECT_TIMEOUT_MILLIS = 10;//请求超时时间
//缓存大小
private static final long HTTP_RESPONSE_DISK_CACHE_MAX_SIZE = 10 * 1024 * 1024;
//OkHttpClient
private OkHttpClient mOkHttpClient;
//API接口
private RetrofitApi httpApi;

private HttpUtil() {
    initOKHttp();
    initRetrofit();
}

public static HttpUtil getInstance() {
    return ClassHolder.instace;
}

private static class ClassHolder {
    static final HttpUtil instace = new HttpUtil();
}

private void initOKHttp() {
    //日志拦截器,专业处理请求过程中的日志 ,header、body数据
    HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
    //根据包的类型控制日志输出与否
    loggingInterceptor.setLevel(BasePackageUtil.isApkDebugable() ? HttpLoggingInterceptor.Level.BODY : HttpLoggingInterceptor.Level.NONE);

    //SSH相关设置,处理https请求的,默认全部信任,不添加的话遇到https请求可能会出异常,WebView,Picasso,Gilde等框架都会有此问题
    SSLParams sslSocketFactory = SSHUtil.getSslSocketFactory();

    mOkHttpClient = new OkHttpClient.Builder()
            .readTimeout(DEFAULT_READ_TIMEOUT_MILLIS, TimeUnit.SECONDS)
            .writeTimeout(DEFAULT_WRITE_TIMEOUT_MILLIS, TimeUnit.SECONDS)
            //设置连接超时时间
            .connectTimeout(DEFAULT_CONNECT_TIMEOUT_MILLIS, TimeUnit.SECONDS)
            //设置缓存
            .cache(getDefaultCache())
            //日志拦截器
            .addInterceptor(loggingInterceptor)
            //头部拦截器
            .addInterceptor(new HeadsInterceptor())
            //设置SSH 兼容https
            .sslSocketFactory(sslSocketFactory.sSLSocketFactory, sslSocketFactory.trustManager)
            //默认全部信任
            .hostnameVerifier(SSHUtil.getHostnameVerifier())
            .build();


}

private void initRetrofit() {
    Retrofit.Builder builder = new Retrofit.Builder()
            //设置网络请求实现
            .client(mOkHttpClient)
            //设置json数据解析实现
            .addConverterFactory(GsonConverterFactory.create())
            //RXJAVA适配器
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create());

    //这里主域名的设置单独来弄,万一后台奇葩,一个app里两个主域名的话可以再建一个API_X的接口类,这里类似的单独再配置他的baseurl
    httpApi = builder.baseUrl(Constants.APP_HOST)
            .build()
            .create(RetrofitApi.class);

    //配置了RxJava2CallAdapterFactory即集合RXjava的话httpApi调用xxx方法可以直接返回Observable,然后拿来subscribe
    //不结合RXjava的话返回httpApi调用xxx方法返回Call对象,然后拿来enqueue发请求

    //结合RXjava的优点:更灵活,链式调用,线程切换方便,各种操作符效果吊炸天。 说白了就是可以在处理很复杂嵌套循环请求的时候利用RXJAVA,简化开发
    //不过RXJAVA自身的学习成本的确是个问题,我到现在也是云里雾里,不过既然是框架,,,先用再说啦!

}

public OkHttpClient getmOkHttpClient() {
    return mOkHttpClient;
}

public RetrofitApi getHttpApi() {
    return httpApi;
}

public Cache getDefaultCache() {
    String dir = BaseFileUtil.getHttpCacheDir();
    File file = new File(dir);
    Cache cache = new Cache(file, HTTP_RESPONSE_DISK_CACHE_MAX_SIZE);
    return cache;
}

}

3.API封装与调用

public interface RetrofitApi {
/*获取首页数据*/
@POST(Constants.FUNCTION_INDEX)
Observable<TDataBean<IndexMultBean>> getIndexData();

/*登录*/
@POST(Constants.FUNCTION_LOGIN)
Observable<TDataBean<UserInfo>> login(@Body JsonObject object);
}

public class ApiManager {
//统一设置线程
private static <T> Observable<T> subscribeOn(Observable<T> observable) {
    return observable.subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread());
}
//获取RetrofitApi实例
private static RetrofitApi getJavaApi() {
    return HttpUtil.getInstance().getHttpApi();
}

/***************************************业务逻辑接口**************************************/
    /*获取首页数据*/
public static Observable<TDataBean<IndexMultBean>> getIndexData() {
    Observable<TDataBean<IndexMultBean>> observable = getJavaApi().getIndexData();
    return subscribeOn(observable);
}

/*获取首页数据*/
public static Observable<TDataBean<UserInfo>> login(String username, String pwd) {
    JsonObject data = new JsonObject();
    data.addProperty("mobile", username);
    data.addProperty("password", pwd);
    data.addProperty("device_token", DeviceUtils.getDeviceId());
    Observable<TDataBean<UserInfo>> observable = getJavaApi().login(data);
    return subscribeOn(observable);
}
}

完整的demo地址:
https://gitee.com/lunguoguo/revised_development_framework.git (已更新)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容