前言:
网络请求可以算是一个应用最基本的功能模块之一了,那么如何让网络请求变的更加方便实用呢?今天我就给大家介绍一下目前最主流的网络请求框架,Retrofit + RxJava + OkHttp,那么接下来,我们先简单介绍一下这三个模块,最后再结合在一起做一个简单的分装。
Retrofit
Retrofit是Square公司开发的一款针对Android网络请求的框架,Retrofit2底层基于OkHttp实现的,OkHttp现在已经得到Google官方认可,目前大部分
app都采用OkHttp做网络请求,其源码详见OkHttp Github。
Retrofit的简单使用
具体参照以下博文
[Android] Retrofit 初步使用
RxJava
RxJava 在 GitHub 主页上的自我介绍是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库)。这就是 RxJava ,概括得非常精准。
好吧,再偷个懒,关于RxJava请参考以下几篇博文:
给 Android 开发者的 RxJava 详解
这可能是最好的RxJava 2.x 教程(完结版)
OkHttp
OkHttp目前已经得到Google的官方认可,也是目前主流的网络请求框架,具体用法,大家参照官网http://square.github.io/okhttp/,毕竟接下来把它和Retrofit和RxJava结合的分装才是重点。
Retrofit + RxJava + OkHttp封装(闪亮登场)
一:创建Retrofit的管理类RetrofitHelper
/**
* 网络请求Retrofit的帮助类
* Created by Administrator on 2017/11/2.
*/
public class RetrofitHelper {
private static final int DEFAULT_TIME_OUT = 30;//超时时间 10s
private static final int DEFAULT_READ_TIME_OUT = 30;
private Retrofit mRetrofit;
private RetrofitHelper(){
final OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS);//连接超时时间
builder.readTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS);//读操作超时时间
// 添加公共参数拦截器
HttpCommonInterceptor commonInterceptor = new HttpCommonInterceptor.Builder()
.addHeaderParams("cookie", OrtherUtil.getCookie(BasicUtil.getUserId()))//添加的公共请求头部(即cookie信息)
.build();
builder.addInterceptor(commonInterceptor);
mRetrofit = new Retrofit.Builder()
.client(builder.build())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(MyGsonConverterFactory.create())
.baseUrl(Interface_Url.HTTPURL)//添加请求的URL地址(前面公共部分)
.build();
}
//使用静态内部类的方式获取单例模式
// private static class SingletonHolder{
// private static final RetrofitHelper INSTANCE = new RetrofitHelper();
// }
//获取RetrofitHelper对象,为保证每次的cookie信息为最新的,所以每次调用都重新给mRetrofit赋值
public static RetrofitHelper getInstance(){
// return SingletonHolder.INSTANCE;
return new RetrofitHelper();
}
/**
* 获取服务对象 以接口的形式
* @param classz 接口类
* @param
* @return
*/
public T getService(Class classz){
return mRetrofit.create(classz);
}
}
其中为了保证每次获取的网络请求中cookie信息都是最新的(cookie中包含时间戳信息),所以每次请求时都是重新构建了retrofit的请求参数,如果项目中的cookie信息固定,则可用上面注释掉的单例模式获取RetrofitHelper
为了方便对请求的结果做统一管理,在构建请求时添加了自定义的
MyGsonConverterFactory类,该类继承Converter.Factory,实现如下:
/**
* 自定义GsonConverterFactory
*/
public final class MyGsonConverterFactory extends Converter.Factory{
/**
* Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and
* decoding from JSON (when no charset is specified by a header) will use UTF-8.
*/
public static MyGsonConverterFactory create() {
return create(new Gson());
}
/**
* Create an instance using {@code gson} for conversion. Encoding to JSON and
* decoding from JSON (when no charset is specified by a header) will use UTF-8.
*/
@SuppressWarnings("ConstantConditions") // Guarding public API nullability.
public static MyGsonConverterFactory create(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
return new MyGsonConverterFactory(gson);
}
private final Gson gson;
private MyGsonConverterFactory(Gson gson) {
this.gson = gson;
}
@Override
public Converter responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
// TypeAdapter> adapter = gson.getAdapter(TypeToken.get(type));
return new MyGsonResponseBodyConverter<>(gson, type);
}
@Override
public Converter, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter> adapter = gson.getAdapter(TypeToken.get(type));
return new MyGsonRequestBodyConverter<>(gson, adapter);
}
}
其中主要修改了responseBodyConverter和requestBodyConverter方法。这两个方法主要是对返回的结果以及请求的参数进行处理,具体实现如下:
/**
* 重写GsonResponseBodyConverter方便获取网络返回的原始数据
* Created by Administrator on 2017/11/3.
*/
final class MyGsonResponseBodyConverter implements Converter{
private final Gson gson;
private final Type type;
MyGsonResponseBodyConverter(Gson gson, Type type) {
this.gson = gson;
this.type = type;
}
@Override
public T convert(ResponseBody value) throws IOException{
JSONObject jsonObject;
String response = value.string();
//Log.e("jk",response);
// BaseResponseBean baseResponse = gson.fromJson(response,type);
try {
jsonObject = new JSONObject(response);
return (T) jsonObject;
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
}
final class MyGsonRequestBodyConverter implements Converter{
private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
private static final Charset UTF_8 = Charset.forName("UTF-8");
private final Gson gson;
private final TypeAdapter adapter;
MyGsonRequestBodyConverter(Gson gson, TypeAdapter adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override public RequestBody convert(T value) throws IOException{
Buffer buffer = new Buffer();
Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
JsonWriter jsonWriter = gson.newJsonWriter(writer);
LogController.i("jk",jsonWriter.toString());
adapter.write(jsonWriter, value);
jsonWriter.close();
return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
}
}
二:定义网络请求返回的实体类(基类)
/**
* 网络请求结果的基类
* Created by Administrator on 2017/11/3.
*/
public class BaseResponseBean{
public int errcode;//错误码
public String errmsg;//错误信息 当errcode不为0时返回
public T replydata;//返回的关键数据,每个接口的对象都不一样
public boolean isSuccess(){
return errcode == 0;//为0时请求成功
}
}
这个返回的基类根据服务器返回的参数类型来定,分为固定参数errcode(错误码)和errmsg(错误信息),以及可变参数replydata(真正返回的数据类),这里返回类型用泛型T表示
三:结合Rxjava定义网络请求工具类
/**
* 网络请求工具类
* Created by Administrator on 2017/11/2.
*/
public class HttpUtils {
/**
* 结合Rxjava进行网络请求
* @param observable
* @param resultListener
* @param
*/
public static void requestNet(final Observable observable, final OnResultListener resultListener){
if(!NetUtil.isNetworkAvailabe(BaseApplication.getAppContext())){//网络不可用
resultListener.onError(new Exception("网络错误"),"网络未连接",-3);
return;
}
setSubscriber(observable, new Observer(){
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(JSONObject jsonObject) {
if(resultListener != null){
LogController.e("jk","请求结果:"+jsonObject.toString());
BaseResponseBean baseResponse = new Gson().fromJson(jsonObject.toString(),BaseResponseBean.class);
if(baseResponse.isSuccess()){//数据返回成功
resultListener.onSuccess(jsonObject);//返回整个json数据
}else{//返回错误码,并进行统一的错误处理
switch(baseResponse.errcode){
case -1:
resultListener.onError(new Exception("服务器错误"),baseResponse.errmsg,baseResponse.errcode);
break;
case 1001:
resultListener.onError(new Exception("请求错误"),baseResponse.errmsg,baseResponse.errcode);
break;
case 1002:
resultListener.onError(new Exception("请求错误"),baseResponse.errmsg,baseResponse.errcode);
break;
case 1003:
resultListener.onError(new Exception("请求错误"),baseResponse.errmsg,baseResponse.errcode);
break;
case 1004:
resultListener.onError(new Exception("请求错误"),baseResponse.errmsg,baseResponse.errcode);
break;
case 1005:
resultListener.onError(new Exception("请求错误"),baseResponse.errmsg,baseResponse.errcode);
break;
default:
resultListener.onError(new Exception("其他错误"),baseResponse.errmsg,baseResponse.errcode);
break;
}
}
}
}
@Override
public void onError(Throwable e) {
if(e != null && resultListener != null){
resultListener.onError(e,e.getMessage(),-2);
}else if(resultListener != null){
resultListener.onError(new Exception("网络错误"),"网络请求失败",-2);
return;
}
}
@Override
public void onComplete() {
}
});
}
public static void setSubscriber(Observable observable, Observer observer){
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer);
}
/**
* 获取RequestBody,用于请求接口时,方便传递参数
* @param jsonObject
* @return
*/
public static RequestBody getRequestBody(JSONObject jsonObject){
//添加传递的参数,以json数据的格式
RequestBody body = RequestBody.create(MediaType.parse("application/json"),jsonObject.toString());
return body;
}
//网络请求接口的回调
public interface OnResultListener{
void onSuccess(T t);
void onError(Throwable error, String msg, int err_code);
}
}
四:定义请求接口和方法,进行网络请求
这里以获取应用最新版本的请求接口做个示范(get请求)
public interface IVersionInter {
@GET(InterConstant.GETVERSONURL)
Observable getVersion();
}
//获取接口对象
IVersionInter service = RetrofitHelper.getInstance().getService(IVersionInter.class);
//调用接口方法,得到返回的observable
Observable observable = service.getVersion();
HttpUtils.requestNet(observable, new HttpUtils.OnResultListener() {
@Override
public void onSuccess(Object o) {
Gson gson = new Gson();
//获取到的版本实体类
VersionRespond respond = gson.fromJson(o.toString(), VersionRespond .class);
}
@Override
public void onError(Throwable error, String msg, int err_code) {
//打印错误
LogController.e(TAG,msg);
}
});
同样的,如果是post请求,只需在接口的方法中添加请求参数即可,改写如下:
public interface IVersionInter {
@POST(InterConstant.GETVERSONURL)
Observable getVersion(@Body RequestBody body);
}
//添加传递的参数,以json数据的格式
RequestBody body = RequestBody.create(MediaType.parse("application/json"), getJsonObject().toString());
//获取接口对象
IVersionInter service = RetrofitHelper.getInstance().getService(IVersionInter.class);
//调用接口方法,得到返回的observable
Observable observable = service.getVersion(body );
HttpUtils.requestNet(observable, new HttpUtils.OnResultListener() {
@Override
public void onSuccess(Object o) {
Gson gson = new Gson();
//获取到的版本实体类
VersionRespond respond = gson.fromJson(o.toString(), VersionRespond .class);
}
@Override
public void onError(Throwable error, String msg, int err_code) {
//打印错误
LogController.e(TAG,msg);
}
});
其中getJsonObject()则返回需要传递的请求参数,并分装成JSONObject的形式返回。