一. 前言(简述)
OkHttp是一个高效的HTTP库
Ø 支持 SPDY ,共享同一个Socket来处理同一个服务器所有请求
Ø 如果SPDY不可用,则通过连接池来减少请求延时;
Ø 无缝的支持GZIP来减少数据流量;
Ø 缓存响应数据来减少重复的网络请求。
二简述在项目中使用自己封装的网络框架
1.首先定义一个管理者OkHttpClientManager 这个类采用单例设计模式,直接上代码。
private static OkHttpClientManager mInstance;
public OkHttpClient mOkHttpClient;//可以在程序外调用OkHttpClientManager.mOkHttpClient.cancel
private Handler mDelivery;
private static final String TAG = "OkHttpClientManager";
private OkHttpClientManager() {
mOkHttpClient = new OkHttpClient();
//OkHttp支持连接,读取和写入超时。
mOkHttpClient.setConnectTimeout(10, TimeUnit.SECONDS);
mOkHttpClient.setWriteTimeout(10, TimeUnit.SECONDS);
mOkHttpClient.setReadTimeout(30, TimeUnit.SECONDS);
//cookie enabled一种预定义策略,表示只接受来自原始服务器的 cookie。
mOkHttpClient.setCookieHandler(new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER));
mDelivery = new Handler(Looper.getMainLooper());
}
public static OkHttpClientManager getInstance() {
if (mInstance == null) {
synchronized (OkHttpClientManager.class) {
if (mInstance == null) {
mInstance = new OkHttpClientManager();
}
}
}
return mInstance;
}
这里给这个client设置了读写超时时间,设置cookie等属性值。
接下来我们就要写常见的Http请求了,当然常见的Http请求用的最多的是get和post啦,下面分别进行封装。
/**
* 异步的post请求
*
* @param url
* @param callback
* @param params
*/
private void _postAsyn(String url, final INetClientHandler callback, Map<String, String> params) {
Param[] paramsArr = map2Params(params);
Request request = buildPostRequest(url, paramsArr);
deliveryResult(callback, request);
}
这里我给出了异步的执行post请求,那么这个INetClientHandler 到底是个什么鬼?往下看!
public interface INetClientHandler {
//状态码为0 表示成功
public void onSuccess(String response);
//网络状态异常
public void onNetFail();
//状态码不为0 状态失败,toast错误信息
public void onStateFail(IErrorBody iErrorBody);
//只要访问网络成功都会执行此方法
public void onFinish();
//状态码不为0返回的JSON串
public void onFailed(String response);
}
打开INetClientHandler 我们可以看出其实这就是个接口,仔细看看接口定义的几个方法,onSuccess,onFinish,onFailed,onStateFailed等接口回调,是不是感觉有种似曾相识的感觉,没错,我们在HttpUtils里面也知道成功和失败的回调,这里我只是把回调的方法写的详细点,(成功,失败,结束,网络状态异常,服务器异常等情况)。
private Param[] map2Params(Map<String, String> params) {
if (params == null) return new Param[0];
int size = params.size();
Param[] res = new Param[size];
Set<Map.Entry<String, String>> entries = params.entrySet();
int i = 0;
for (Map.Entry<String, String> entry : entries) {
res[i++] = new Param(entry.getKey(), entry.getValue());
}
return res;
}
这段代码主要封装我们的post提交的map,我们把它封装成一个数组,因为往服务器里面传递的数据我用Map来存储。
private Request buildPostRequest(String url, Param[] params) {
if (params == null) {
params = new Param[0];
}
FormEncodingBuilder builder = new FormEncodingBuilder();
for (Param param : params) {
if (!CommonUtil.isEmpty(param.value)) {
builder.add(param.key, param.value);
}
}
RequestBody requestBody = builder.build();
return new Request.Builder()
.url(url)
.tag(TAG)
.post(requestBody)
.build();
}
注:这里的Param封装了键值对
public static class Param {
public Param() {
}
public String key;
public String value;
public Param(String key, String value) {
this.key = key;
this.value = value;
}
}
这一段代码相信大家都能看懂,只是封装了一个请求而已,看到这里,我们怎样传一个请求呢,往下看
private void deliveryResult(final INetClientHandler callback, Request request) {
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(final Request request, final IOException e) {
sendFailedStringCallback(request, e, callback);
}
@Override
public void onResponse(final Response response) {
try {
final String string = response.body().string();
sendSuccessResultCallback(string, callback);
} catch (IOException e) {
sendFailedStringCallback(response.request(), e, callback);
}
}
});
}
这部分传递的就是请求结果了,我们把请求后的结果自己去进行操作,来个callback吧!
private void sendFailedStringCallback(final Request request, final Exception e, final INetClientHandler callback) {
mDelivery.post(new Runnable() {
@Override
public void run() {
if (callback != null) {
callback.onNetFail();//记得这里吗 是我们接口定义的回调啊
callback.onFinish();
}
}
});
}
这里给出了网络状态异常
private void sendSuccessResultCallback(final Object object, final INetClientHandler callback) {
mDelivery.post(new Runnable() {
@Override
public void run() {
if (callback != null) {
Log.i("test", object.toString());
ResponseBody body = ResponseBody.parse(object.toString());
if (body.isOK()) {
callback.onSuccess(object.toString());
callback.onFinish();
} else {
IErrorBody ieb = IErrorBody.CODEERROR;
ieb.setCode(body.getCode());
ieb.setMessage(body.getMessage());
callback.onFailed(object.toString());
callback.onStateFail(ieb);
callback.onFinish();
}
}
}
});
}
这里就是我们成功时候的回调啦,client类封装完毕,但我们怎么给出去呢,我们提供了一个方法,调用就可以啦!
//*************对外公布的方法************
public static void postAsyn(String url, final INetClientHandler callback, Map<String, String> params) {
getInstance()._postAsyn(url, callback, params);
}
这是封装内部做的事情,那么怎么使用呢?这就让NetManager登场啦!
举个栗子
/**
* 注册
* @param absParams
* @param handler
*/
public static void regsiter(AbsHashParams absParams, final INetClientHandler handler){
Map<String,String> map= ParamsHelper.getParams(absParams);
OkHttpClientManager.postAsyn(UrlInterface.API_REGISTER, handler, map);
}
显然这是项目中注册的接口,只需要直接调用就行啦 NetManager.regsiter(),当然我们要传递点参数啦 AbsHashParams 登场,这个类是个抽象类。
public abstract class AbsHashParams extends AbsParams{
@Override
public Map<String, String> getMap() {
Map<String,String> map=new HashMap<>();
//传递共有的参数,方便以后封板加密或者增加共有参数
map.put("channel_id", "1");
// if(CommonParams.getSign()!=null){
// map.put("sign", CommonParams.getSign());
//
// CommonUtil.getSign(context,"com.luochen.reader")
// }
map.put("sign", CommonUtil.getSign(AppUtils.getAppContext(),"com.luochen.reader"));
map.put("device_id", CommonParams.getDevice_id());
map.put("timestamp", System.currentTimeMillis() + "");
if(StringUtils.isValid(CommonParams.getToken())){
map.put("uid", CommonParams.getUid());
map.put("token", CommonParams.getToken());
}
// map.put("uid", CommonParams.getUid());
// map.put("token", CommonParams.getToken());
getOtherParams(map);
return map;
}
public abstract Map<String, String> getOtherParams(Map<String,String> map);
}
我们把每次需要的参数都放在上面的方法,如果需要其他的就重写getOtherParams()方法,返回个map就行了,上面的参数读者不必深究,无外乎就是token 签名 用户id等基础信息,这些读者可以根据自身项目去重新写。
注意:上面说到INetClientHandler ,当然我们不需要时刻的去重写不需要的接口,这违反了设计模式6大原则的内容,即我们不要依赖我们不需要的接口,即接口隔离原则。所以就得重写啦
public class NetClientHandler implements INetClientHandler {
private Context context;
public NetClientHandler(@NonNull Context context) {
this.context = context;
}
@Override
public void onSuccess(String response) {
Log.i("test", "response=" + response);
}
@Override
public void onNetFail() {
if (context != null) {
// ToasterHelper.show(context, "您的网络异常,请检查网络!!");
Toast.makeText(context,"您的网络异常,请检查网络!!",Toast.LENGTH_SHORT).show();
}
// else if (TUtils.isValid(AppUtils.getAppContext())) {
// ToasterHelper.show(context, "您的网络异常,请检查网络!!");
// }
}
@Override
public void onStateFail(IErrorBody iErrorBody) {
if (!CommonUtil.isEmpty(iErrorBody)) {
if(iErrorBody.getMessage()!=null){
// ToasterHelper.show(context.getApplicationContext(), iErrorBody.getMessage().toString());
Toast.makeText(context,iErrorBody.getMessage().toString(),Toast.LENGTH_SHORT).show();
}
}
if (iErrorBody.getCode() == 1008) {
return;
} else {
if (!CommonUtil.isEmpty(iErrorBody.getMessage()))
// ToasterHelper.show(context, iErrorBody.getMessage());
Toast.makeText(context,iErrorBody.getMessage(),Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFinish() {
}
@Override
public void onFailed(String response) {
}
}
//注册
NetManager.regsiter(new AbsHashParams() {
@Override
public Map<String, String> getOtherParams(Map<String, String> map) {
//所有传递的数据
map.put("username","yuan");
map.put("password","123");
return map;
}
}, new INetClientHandler() {
@Override
public void onSuccess(String response) {
//成功时 response返回的json
}
@Override
public void onNetFail() {
//网络失败时
}
@Override
public void onStateFail(IErrorBody iErrorBody) {
//服务器异常
}
@Override
public void onFinish() {
//结束时 这里可以给出关闭提示框等等
}
@Override
public void onFailed(String response) {
//失败时
}
});
这里我们给出了具体处理方法,对服务器错误的处理,对网络错误的处理,如果不用就让父类处理,如果想其他的就重写这个方法。处理特殊的需求。至此,本次的封装OkHttp主要的类就到这里了,难免代码有误,请指正。