您的位置:首页 > 理论基础 > 计算机网络

网络框架的简单封装

2017-01-05 13:18 323 查看
一. 前言(简述)

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主要的类就到这里了,难免代码有误,请指正。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  网络框架