我这里的网络请求是用的装饰者模式去写的,什么是装饰者模式呢?在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。我的理解就是一个接口,两个实现类,一个实现类负责调用接口的方法,另一个类负责功能的具体实现。本文中所提到的代码都是伪代码,最后会给出完整的,最初版本的项目框架。不包含任何业务逻辑

 
项目结构.png

  容我一个一个来说,首先,我们一般请求网络的时候,会有统一的返回数据格式,一个是需要判断返回code码的,就比方说登录功能,那登录成功,还是失败,我们只用判断code码即可,这种类型,我们统一是HttpNoResult。还有一个是返回数据的,就比方说查一个列表数据。这里我们统一的是HttpResult。我先给出这两个类的代码:

package com.haichenyi.myproject.model.http;

/**
* Author: 海晨忆
* Date: 2018/2/23
* Desc:没有解析数据的返回
*/
public class HttpNoResult {
private int code;
private String msg; public int getCode() {
return code;
} public HttpNoResult setCode(int code) {
this.code = code;
return this;
} public String getMsg() {
return msg;
} public HttpNoResult setMsg(String msg) {
this.msg = msg;
return this;
} @Override
public String toString() {
return "HttpNoResult{" + "code=" + code + ", msg='" + msg + '\'' + '}';
}
}
package com.haichenyi.myproject.model.http;

import com.google.gson.annotations.SerializedName;

/**
* Author: 海晨忆
* Date: 2018/2/23
* Desc:有解析数据的返回
*/
public class HttpResult<T> {
private int code;
private String msg;
@SerializedName(value = "result")
private T data; public int getCode() {
return code;
} public HttpResult setCode(int code) {
this.code = code;
return this;
} public String getMsg() {
return msg;
} public HttpResult setMsg(String msg) {
this.msg = msg;
return this;
} public T getData() {
return data;
} public HttpResult setData(T data) {
this.data = data;
return this;
} @Override
public String toString() {
return "HttpResult{" + "code=" + code + ", msg='" + msg + '\'' + ", data=" + data + '}';
}
}

 这里我就需要说一点,有数据返回的时候,每个数据类型都是不一样的,所以,这里我用的泛型传递,不同的数据类型,传不同的bean对象

  言归正传,我们来说说网络请求的一个接口,两个实现类。

一个接口—HttpHelper

package com.haichenyi.myproject.model.http;

import io.reactivex.Flowable;

/**
* Author: 海晨忆
* Date: 2018/2/23
* Desc:网络接口,接口参数Token统一处理,方法中不传Token
*/
public interface HttpHelper {
/**
* 登录时获取验证码.
*
* @param phone 手机号
* @return {"code":0}
*/
Flowable<HttpNoResult> loginCode(String phone);
/*Flowable<HttpResult<Login>> login(String phone, String code);
Flowable<HttpResult<List<DiyBean>>> diyKeys(String allId);*/
}

 Flowable是RxJava2.0新增的,所以说RxJava完美兼容Retrofit,泛型就是我们需要解析的数据

  1. loginCode方法是说返回数据,我们只用判断是否是成功还是失败,

  2. login方法是说返回数据是一个Login对象,至于对象是什么内容,那就是和你们后台确认了

  3. diyKeys方法就是说,返回数据是一个list对象,每个list的item是DiyBean对象

package com.haichenyi.myproject.model;

import com.haichenyi.myproject.model.http.HttpHelper;
import com.haichenyi.myproject.model.http.HttpNoResult; import io.reactivex.Flowable; /**
* Author: 海晨忆
* Date: 2018/2/23
* Desc:网络请求的实现类
*/
public class DataHelper implements HttpHelper {
private HttpHelper http; public DataHelper(HttpHelper http) {
this.http = http;
} @Override
public Flowable<HttpNoResult> loginCode(String phone) {
return http.loginCode(phone);
}
}

DataHelper是HttpHelper的实现类,他的唯一作用就是调用接口的方法即可,具体的功能实现是后面一个类,这里需要说明的是这个类的构造方法要public表示,因为他要dagger生成,用private或者protected表示无法生成。

package com.haichenyi.myproject.model.http;

import com.haichenyi.myproject.model.http.api.HttpApi;

import io.reactivex.Flowable;

/**
* Author: 海晨忆
* Date: 2018/2/23
* Desc: 网络接口Retrofit实现
*/
public class RetrofitHelper implements HttpHelper{
private HttpApi httpApi; @Inject
RetrofitHelper(HttpApi httpApi) {
this.httpApi = httpApi;
} @Override
public Flowable<HttpNoResult> loginCode(String phone) {
return httpApi.loginCode(phone);
}
}

RetrofitHelper类作为HttpHelper接口的实现类,他是具体功能的实现类,为什么说他是具体功能的实现类呢?因为,他是调用HttpApi接口的方法。HttpApi接口是干什么用的呢?

package com.haichenyi.myproject.model.http.api;

import com.haichenyi.myproject.model.http.HttpNoResult;
import com.haichenyi.myproject.model.http.ProtocolHttp; import io.reactivex.Flowable;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST; /**
* Author: 海晨忆
* Date: 2018/2/23
* Desc:网络请求接口api
*/
public interface HttpApi {
/**
* 登录时获取验证码.
*
* @param phone 手机号
* @return {"code":0}
*/
@FormUrlEncoded
@POST(ProtocolHttp.METHOD_LOGIN_CODE)
Flowable<HttpNoResult> loginCode(@Field("phone") String phone);
}

这个就是Retrofit的网络请求的方式,看不懂?这个就是Retrofit的东西了
方法注解,包含@GET、@POST、@PUT、@DELETE、@PATH、@HEAD、@OPTIONS、@HTTP。
标记注解,包含@FormUrlEncoded、@Multipart、@Streaming。
参数注解,包含@Query、@QueryMap、@Body、@Field,@FieldMap、@Part,@PartMap。
其他注解,包含@Path、@Header、@Headers、@Url。

这里我们还差一个接口

package com.haichenyi.myproject.model.http;

/**
* Author: 海晨忆
* Date: 2018/2/23
* Desc:
*/
public interface ProtocolHttp {
String HTTP_HOST = "http://xxx.xx.xxx.xxx:8080/app/con/";
String HTTP_COMMON = "common/";
String METHOD_LOGIN_CODE = HTTP_COMMON + "code";//登录发送验证码
}

如上,这里需要注意的是不能以""结尾,然后就是,跟你们后台商量,格式不要错了,尽量就只有接口名字不同,接口名字前面部分都是一样的。

  到此,这里基本上就说完了,那么有同鞋就会问了,接口定义方法的时候,我们知道该如何写返回数据类型呢?这个我就不知道了,你得问你们后台,根据后台返回的数据类型去写对应的bean类。推荐一个功能PostMan。

  到目前为止,我们都还没有初始化网络请求的参数,这些网络请求的参数在哪里初始化呢?这些参数,我们就只用初始化一次,我们就想到了dagger的全局单例模式,没错,就是这个,我们上一篇写了很多没有用的东西,里面有一个HttpModule

package com.haichenyi.myproject.di.module;

import com.haichenyi.myproject.di.qualifier.ApiUrl;
import com.haichenyi.myproject.model.http.ProtocolHttp;
import com.haichenyi.myproject.model.http.api.HttpApi; import java.util.concurrent.TimeUnit; import javax.inject.Singleton; import dagger.Module;
import dagger.Provides;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory; /**
* Author: 海晨忆
* Date: 2018/2/23
* Desc:网络请求的参数初始化
*/
@Module
public class HttpModule {
@Provides
@Singleton
OkHttpClient.Builder providesOkHttpHelper() {
//请求读写超时时间
return new OkHttpClient.Builder()
.connectTimeout(, TimeUnit.SECONDS)
.readTimeout(, TimeUnit.SECONDS)
.writeTimeout(, TimeUnit.SECONDS);
} @Provides
@Singleton
OkHttpClient provideClient(OkHttpClient.Builder builder) {
return builder
// .addInterceptor(new MyHttpInterceptor())
.build();
} @Provides
@Singleton
Retrofit.Builder providesRetrofitBuilder() {
return new Retrofit.Builder();
} @Provides
@Singleton
HttpApi provideApi(@ApiUrl Retrofit retrofit) {
return retrofit.create(HttpApi.class);
} @Provides
@Singleton
@ApiUrl
Retrofit providesApiRetrofit(Retrofit.Builder builder, OkHttpClient client) {
return createRetrofit(builder, client, ProtocolHttp.HTTP_HOST);//这里就是你的网络请求的url
} private Retrofit createRetrofit(Retrofit.Builder builder, OkHttpClient client, String host) {
return builder.client(client)
.baseUrl(host)
.addConverterFactory(GsonConverterFactory.create())//添加gson自动解析,我们不用关
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
}

如上代码,注释写的都有,考过去用就行了

在AppModule里面添加如下代码

package com.haichenyi.myproject.di.module;

import com.haichenyi.myproject.base.MyApplication;
import com.haichenyi.myproject.model.DataHelper;
import com.haichenyi.myproject.model.http.HttpHelper;
import com.haichenyi.myproject.model.http.RetrofitHelper; import javax.inject.Singleton; import dagger.Module;
import dagger.Provides; /**
* Author: 海晨忆
* Date: 2018/2/23
* Desc:
*/
@Module
public class AppModule {
private MyApplication application; public AppModule(MyApplication application) {
this.application = application;
} @Provides
@Singleton
DataHelper provideDataHelper(HttpHelper httpHelper) {
return new DataHelper(httpHelper);
} @Provides
@Singleton
HttpHelper provideHttpHelper(RetrofitHelper retrofitHelper) {
return retrofitHelper;
}
}

这里都是dagger了生成全局单例对象需要的东西

在AppComponent里面添加如下代码

package com.haichenyi.myproject.di.component;

import com.haichenyi.myproject.di.module.AppModule;
import com.haichenyi.myproject.di.module.HttpModule;
import com.haichenyi.myproject.model.DataHelper; import javax.inject.Singleton; import dagger.Component; /**
* Author: 海晨忆
* Date: 2018/2/23
* Desc:
*/
@Singleton
@Component(modules = {AppModule.class, HttpModule.class})
public interface AppComponent {
DataHelper getDataHelper();
}

在BaseMvpPresenter里面添加如下代码

package com.haichenyi.myproject.base;

import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable; /**
* Author: 海晨忆
* Date: 2018/2/23
* Desc:
*/
public class BaseMvpPresenter<T extends BaseView> implements BasePresenter<T> {
protected T baseView;
private CompositeDisposable disposables; @Override
public void attachView(T baseView) {
this.baseView = baseView;
} protected void addSubscribe(Disposable disposable) {
if (null == disposables) {
disposables = new CompositeDisposable();
}
disposables.add(disposable);
} @Override
public void detachView() {
this.baseView = null;
unSubscribe();
} private void unSubscribe() {
if (null != disposables) {
disposables.clear();
disposables = null;
}
}
}

至此,就全部写完了,关于网络请求的内容。调用方式如下:

package com.haichenyi.myproject.presenter;

import com.haichenyi.myproject.base.BaseMvpPresenter;
import com.haichenyi.myproject.base.MyApplication;
import com.haichenyi.myproject.contract.MainContract;
import com.haichenyi.myproject.model.DataHelper; import javax.inject.Inject; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers; /**
* Author: 海晨忆
* Date: 2018/2/23
* Desc:
*/
public class MainPresenter extends BaseMvpPresenter<MainContract.IView>
implements MainContract.Presenter {
private DataHelper dataHelper;
@Inject
MainPresenter() {
dataHelper = MyApplication.getAppComponent().getDataHelper();
} @Override
public void loadData() {
addSubscribe(dataHelper.loginCode("134xxxxxxxx")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe());
// baseView.showTipMsg("加载数据");
}
}

记得在清单文件里面,加上网络权限

<uses-permission android:name="android.permission.INTERNET"/>

网络请求,这样调用之后在哪处理呢?我给出我的几个处理的工具类。首先,按如下图设置1.8支持lambda表达式

 
配置.png

然后添加如下几个类

HttpCode

package com.haichenyi.myproject.model.http;

/**
* Author: 海晨忆.
* Date: 2017/12/21
* Desc: 网络请求状态码
*/
public interface HttpCode {
/**
* 成功.
*/
int SUCCESS = ;
/**
* 参数为空.
*/
int NO_PARAMETER = ;
/**
* 服务器错误.
*/
int SERVER_ERR = ;
}

ApiException

package com.haichenyi.myproject.model.http;

/**
* Author: 海晨忆.
* Date: 2017/12/21
* Desc: 接口异常判断处理
*/
public class ApiException extends Exception {
private int code; @SuppressWarnings("unused")
public ApiException(int code) {
this.code = code;
} public ApiException(int code, String message) {
super(message);
this.code = code;
} public int getCode() {
return code;
} public ApiException setCode(int code) {
this.code = code;
return this;
}
}

MyRxUtils

package com.haichenyi.myproject.model.http;

import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.FlowableTransformer;
import io.reactivex.Scheduler;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers; /**
* Author: 海晨忆.
* Date: 2017/12/27
* Desc:切换线程的工具类
*/
public class MyRxUtils {
/**
* 从其他线程转到主线程.
*
* @param scheduler Schedulers.io()等等
* @param <T> t
* @return FlowableTransformer
*/
public static <T> FlowableTransformer<T, T> toMain(Scheduler scheduler) {
return upstream -> upstream.subscribeOn(scheduler).observeOn(AndroidSchedulers.mainThread());
} public static <T> FlowableTransformer<HttpResult<T>, T> handResult() {
return upstream -> upstream.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap(tHttpResult -> {
if (tHttpResult.getCode() == HttpCode.SUCCESS) {
return /*createData(tHttpResult.data)*/Flowable.just(tHttpResult.getData());
} else {
return Flowable.error(new ApiException(tHttpResult.getCode(), tHttpResult.getMsg()));
}
});
} private static <T> Flowable<T> createData(final T data) {
return Flowable.create(e -> {
e.onNext(data);
e.onComplete();
}, BackpressureStrategy.ERROR);
}
}

MySubscriber

package com.haichenyi.myproject.model.http;

import com.haichenyi.myproject.base.BaseView;
import io.reactivex.subscribers.ResourceSubscriber; /**
* Author: 海晨忆.
* Date: 2017/12/21
* Desc:
*/
public abstract class MySubscriber<T> extends ResourceSubscriber<T> {
private BaseView baseView;
private boolean showLoading; public MySubscriber(BaseView baseView) {
this.baseView = baseView;
} public MySubscriber(BaseView baseView, boolean showLoading) {
this.baseView = baseView;
this.showLoading = showLoading;
} @Override
protected void onStart() {
super.onStart();
if (null != baseView && showLoading) {
baseView.showLoading();
}
} @Override
public void onError(Throwable t) {
if (null == baseView) {
return;
}
baseView.hideLoading();
if (t instanceof ApiException) {
ApiException apiException = (ApiException) t;
switch (apiException.getCode()) {
case HttpCode.NO_PARAMETER:
baseView.showTipMsg("参数为空");
break;
case HttpCode.SERVER_ERR:
baseView.showTipMsg("服务器错误");
break;
default:
break;
}
}
} @Override
public void onComplete() {
if (null != baseView) {
baseView.hideLoading();
}
}
}

这几个类不想多做解释,结合注释,仔细看几遍,就知道是干嘛用的了

加上这几个之后调用方式就变成了以下的方式:

package com.haichenyi.myproject.presenter;

import com.haichenyi.myproject.base.BaseMvpPresenter;
import com.haichenyi.myproject.base.MyApplication;
import com.haichenyi.myproject.contract.MainContract;
import com.haichenyi.myproject.model.DataHelper;
import com.haichenyi.myproject.model.http.HttpNoResult;
import com.haichenyi.myproject.model.http.MyRxUtils;
import com.haichenyi.myproject.model.http.MySubscriber; import javax.inject.Inject; import io.reactivex.schedulers.Schedulers; /**
* Author: 海晨忆
* Date: 2018/2/23
* Desc:
*/
public class MainPresenter extends BaseMvpPresenter<MainContract.IView>
implements MainContract.Presenter {
private DataHelper dataHelper; @Inject
MainPresenter() {
dataHelper = MyApplication.getAppComponent().getDataHelper();
} @Override
public void loadData() {
addSubscribe(dataHelper.loginCode("134xxxxxxxx")
.compose(MyRxUtils.toMain(Schedulers.io()))
.subscribeWith(new MySubscriber<HttpNoResult>(baseView, true) {
@Override
public void onNext(HttpNoResult httpNoResult) { }
}));
// baseView.showTipMsg("加载数据");
}
}

Android 从零开始搭建一个主流项目框架—RxJava2.0+Retrofit2.0+OkHttp的更多相关文章

  1. vue-用Vue-cli从零开始搭建一个Vue项目

    Vue是近两年来比较火的一个前端框架(渐进式框架吧). Vue两大核心思想:组件化和数据驱动.组件化就是将一个整体合理拆分为一个一个小块(组件),组件可重复使用:数据驱动是前端的未来发展方向,释放了对 ...

  2. 从零开始搭建一个react项目

    Nav logo 120 发现 关注 消息 4 搜索 从零开始搭建一个react项目 96 瘦人假噜噜 2017.04.23 23:29* 字数 6330 阅读 32892评论 31喜欢 36 项目地 ...

  3. 手把手教你从零开始搭建SpringBoot后端项目框架

    原料 新鲜的IntelliJ IDEA.一双手.以及电脑一台. 搭建框架 新建项目 打开IDE,点击File -> New Project.在左侧的列表中的选择Maven项目,点击Next. 填 ...

  4. 搭建一个SSH项目框架的步骤

    1.导入jar包(38个) 2.配置文件 applicationContext,xml (beans.xml) (数据源.LocalSessionFactoryBean.事务管理器.事务通知.AOP切 ...

  5. 从零开始搭建一个PaaS平台 - 我们要做什么

    前言 从最开始的小公司做小网站,到现在进入现在的公司做项目,发现小公司里很多很多工作都是重复的劳动(增删改查),不过想想也是,业务软件最基础的东西不就是增删改查吗. 但是很多时候,这种业务逻辑其实没有 ...

  6. Github+yeoman+gulp-angular初始化搭建angularjs前端项目框架

    在上篇文章里面我们说到了Github账号的申请与配置 那么当你有了Github账号并创建了一个自己的Github项目之后,首要的当然是搭建自己的项目框架啦! 本人对自己的定位是web前端狗,常用开发框 ...

  7. 从零开始搭建一个简单的基于webpack的vue开发环境

    原文地址:https://segmentfault.com/a/1190000012789253?utm_source=tag-newest 从零开始搭建一个简单的基于webpack的react开发环 ...

  8. 基于 Express 搭建一个node项目 - 起步

    一,如何基于 Express 搭建一个node项目 什么是Express 借用官方的介绍,Express是一个基于Node.js平台的极简.灵活的web应用开发框架,它提供了一系列强大的特性,帮助你创 ...

  9. 完整搭建一个vue项目

    目录 一. 搭建一个vue项目的完整步骤 二. 卸载vue-cli 三. 完全卸载webpack 一. 搭建一个vue项目的完整步骤 1.安装node.js 下载地址 # 检查是否安装成功 node ...

随机推荐

  1. Learning Python 008 正则表达式-002 findall()方法

    Python 正则表达式 - findall()方法 重点 findall()方法的使用 - 程序讲解 简单的符号的使用 正则表达式的库文件是re,先导入库文件: import re .的使用举例 # ...

  2. unreal3窗口锁定鼠标开关

    GameViewportClient中有个变量控制是否显示硬件鼠标: var transient bool bDisplayHardwareMouseCursor 也就是系统的光标,一般通过该类中的函 ...

  3. 7、sraToolkit安装使用

    参考:http://blog.csdn.net/Cs_mary/article/details/78378552        ###prefetch 参数解释 https://www.ncbi.nl ...

  4. GC偏好的校正与偏好程度的评估

    在二代测序仪上测出的数据,通常都会表现出测序深度与GC 含量的相关性,称为GC bias. GC bias校正 为了后续生物信息分析更加准确,通常需要做GC bias的校正. 2010 年 steve ...

  5. Luogu 2839 [国家集训队]middle

    感觉这题挺好的. 首先对于中位数最大有一个很经典的处理方法就是二分,每次二分一个数组中的下标$mid$,然后我们把$mid$代回到原来的数组中检查,如果一个数$a_{i} \geq mid$,那么就把 ...

  6. spring-cloud 服务优雅下线

      在集群环境下,zuul后面的api服务一般会有多个实例,当下线某个实例时,如果使用 kill -9 pid 的方式,会造成这个服务在eureka中还存在,请求还会路由到这个服务上面,造成500,所 ...

  7. TMF大数据分析指南 Unleashing Business Value in Big Data(一)

    大数据分析指南 TMF Frameworx最佳实践 Unleashing Business Value in Big Data 前言 此文节选自TMF Big Data Analytics Guide ...

  8. Loadrunner监控服务器资源

    LoadRunner 加载监听服务器的步骤如下: 1.在 LoadRunner Controller 下,将工作面板切换到 Run状态,Available Graphs 栏 ,System Resou ...

  9. EasyUI+MVC4实现后台管理系统一:登陆和进入后台界面

    首先实现登陆: 未完待续...

  10. [Xcode 实际操作]四、常用控件-(7)UIStepper控件的使用

    目录:[Swift]Xcode实际操作 本文将演示步进控件的基本用法.步进控件常用于小范围数值的调整. 在项目导航区,打开视图控制器的代码文件[ViewController.swift] import ...