本文简述了为何选择okhttp做为本身的项目网络库,和如何二次封装为module便于使用php
注:进阶版MyOkHttp见文章:java
juejin.im/post/59c4be…android
该系列文章会不断更新Android项目开发中一些好的架构和小技巧git
系列一 Android架构系列-基于MVP建立适合本身的架构
系列二 Android架构系列-如何优美的写Intent
系列三 Android架构系列-开发规范
系列四 Android架构系列-封装本身的okhttp
系列五 Android架构系列-MVP架构的实际应用github
原本项目的网络库选择的搭配是最流行的retrofit+okhttp+gson.以下图版本库里还有记录。json
But!后来遇到了这样的问题:服务端提供的API没法遵循Restful的API格式,并且不一样模块因为分服务开发的,也不能保证格式一致。致使API接口层的实现十分牵强。最终api层的编写不能专一于业务,拔苗助长。(最起码如今的服务端还不适合与retrofit的使用)api
最后决定放弃使用retrofit,使用本身二次封装的okhttp。网络
封装过程当中参考了:架构
hongyang的Android OkHttp彻底解析 是时候来了解OkHttp了ide
赵凯强的开源项目OkHttpPlus
先说封装好的okhttp+gson如何使用。(封装了POST请求,GET请求,上传文件,下载文件,取消请求和Gson转换等功能)
Map<String, String> params = new HashMap<String, String>();
params.put("name", "tsy");
MyOkHttp.get().post(this, "http://192.168.3.1/test_okhttp.php", params, new JsonResponseHandler() {
@Override
public void onSuccess(int statusCode, JSONObject response) {
LogUtils.v(TAG, statusCode + " " + response);
}
@Override
public void onFailure(int statusCode, String error_msg) {
LogUtils.v(TAG, statusCode + " " + error_msg);
}
});复制代码
Map<String, String> params = new HashMap<String, String>();
params.put("name", "tsy");
MyOkHttp.get().get(this, "http://192.168.3.1/test_okhttp.php", params, new RawResponseHandler() {
@Override
public void onSuccess(int statusCode, String response) {
LogUtils.v(TAG, statusCode + " " + response);
}
@Override
public void onFailure(int statusCode, String error_msg) {
LogUtils.v(TAG, statusCode + " " + error_msg);
}
});复制代码
Map<String, String> params = new HashMap<String, String>();
params.put("name", "tsy");
Map<String, File> files = new HashMap<String, File>();
File file = new File(Environment.getExternalStorageDirectory() + "/com.ci123.service.splashandroid/splash/1.png");
files.put("avatar", file);
MyOkHttp.get().upload(this, "http://192.168.3.1/test_post.php", params, files, new GsonResponseHandler<BB>() {
@Override
public void onFailure(int statusCode, String error_msg) {
LogUtils.v(TAG, statusCode + " " + error_msg);
}
@Override
public void onSuccess(int statusCode, BB response) {
LogUtils.v(TAG, statusCode + " " + response.ret);
}
@Override
public void onProgress(long currentBytes, long totalBytes) {
LogUtils.v(TAG, currentBytes + "/" + totalBytes);
}
});复制代码
MyOkHttp.get().download(this, "http://192.168.3.1/output_tmp.jpg",
Environment.getExternalStorageDirectory() + "/com.tsy.splashandroid/", "1.jpg",
new DownloadResponseHandler() {
@Override
public void onFinish(File download_file) {
LogUtils.v(TAG, "onFinish:" + download_file.getPath());
}
@Override
public void onProgress(long currentBytes, long totalBytes) {
LogUtils.v(TAG, currentBytes + "/" + totalBytes);
}
@Override
public void onFailure(String error_msg) {
LogUtils.v(TAG, error_msg);
}
});复制代码
MyOkHttp.get().cancel(this);复制代码
post,get,upload3个接口能够选择返回格式为普通Json仍是Gson
普通json
回调继承JsonResponseHandler,例如POST请求的例子
gson
回调继承GsonResponseHandler,并设置泛型T,例如Upload请求的例子
raw原始数据
回调继承RawResponseHandler,例如GET请求例子
源码集成在了BaseAndroidProject中做为网络底层模块,以module方式封装。其余项目能够直接module拿过来引入项目便可使用。
BaseAndroidProject的Github地址:
github.com/tsy12321/Ba…
源码API入口在MyOkhttp文件中。POST请求和GET请求的实现很简单。在这我主要说明如何封装gson response和上传下载的进度监听。
gson最后封装成了以下的使用形式:
MyOkHttp.get().post(this, "http://192.168.3.1/test_okhttp.php", params, new GsonResponseHandler<BB>() {
@Override
public void onFailure(int statusCode, String error_msg) {
LogUtils.v(TAG, statusCode + " " + error_msg);
}
@Override
public void onSuccess(int statusCode, BB response) {
LogUtils.v(TAG, statusCode + " " + response.ret);
}
});复制代码
gson response与普通json返回不一样的是,在GsonResponseHandler的构造函数中使用反射机制动态获取到了自己的泛型类型,而后将该泛型类型转化为了Gson可使用的Type保存起来。这样在结果回调时就可使用该Type转为Gson。
public abstract class GsonResponseHandler<T> implements IResponseHandler {
Type mType;
public GsonResponseHandler() {
Type myclass = getClass().getGenericSuperclass(); //反射获取带泛型的class
if (myclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
}
ParameterizedType parameter = (ParameterizedType) myclass; //获取全部泛型
mType = $Gson$Types.canonicalize(parameter.getActualTypeArguments()[0]); //将泛型转为type
}
public final Type getType() {
return mType;
}
public abstract void onSuccess(int statusCode, T response);
@Override
public void onProgress(long currentBytes, long totalBytes) {
}
}复制代码
而后在okhttp得到到response后,判断到responseHandler是gson,就将结果转为gson格式。
if(mResponseHandler instanceof JsonResponseHandler) {
...
} else if(mResponseHandler instanceof GsonResponseHandler) {
mHandler.post(new Runnable() {
@Override
public void run() {
try {
Gson gson = new Gson();
((GsonResponseHandler)mResponseHandler).onSuccess(response.code(),
gson.fromJson(response_body, ((GsonResponseHandler)mResponseHandler).getType()));
} catch (Exception e) {
LogUtils.e("onResponse fail parse gson, body=" + response_body, e);
mResponseHandler.onFailure(response.code(), "fail parse gson, body=" + response_body);
}
}
});
}复制代码
该部分参考了赵凯强的-开源项目OkHttpPlus 里面说明的比较清楚。大概的原理就是使用okio分别重写requestbody和responsebody,在body中设置进度监听返回。just so so。详细原理能够直接跳转博客进行学习啊,在这就不从新造轮子了。
最终,okhttp被我封装为了一个module,在这个module中就会引入gson和okhttp了,因此不把它导出为jar包。之后的网络底层库就用这个module啦!
更多文章关注个人公众号