通常我们在写项目时都会使用第三方的网络库,毕竟对于做项目还是不要重复造轮子的好。但是有时候随着业务的变更原有第三方库已经不能满足项目的需求了,这时候我们就不得不自己扩展或者替换原有第三方库了,但是对于网络库这种使用频率很高的第三方库需要替换的地方就太多了,稍有不慎还会出错。
为了避免这种情况的发生,我们需要对使用频繁的第三方库进行二次封装,抽象出一个统一的接口,这样,在你所有的项目中的网络访问都是这一个接口,既保证了代码风格的统一有容易维护。如果你想替换某个库,只需要替换接口内的实现方法就好,其他的根本不用动。
下面就开始动手来实现吧:
- 首先我们要形成一个对外的统一接口,这个接口不可以改变,需要改变的只是实现类的内部方法。实现这个需求可以用建造者模式。
- 抽取所有网络请求的公共部分,一般来说,网络请求肯定会有请求头,请求参数,请求方法,请求地址这几个参数的。而请求头,请求参数一半可以是多个键值对,所以可以用map来接受。
- 封装常用的功能,比如是否加载loading,返回结果的回调处理等。
package com.liu.simple.simple.utils;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.v4.util.ArrayMap;
import android.text.TextUtils;
import android.util.Log;
import com.liu.simple.simple.SimpleApplication;
import org.xutils.common.Callback;
import org.xutils.http.HttpMethod;
import org.xutils.http.RequestParams;
import org.xutils.x;
import java.io.File;
import java.util.Map;
/**
* Author: liukun on 16/8/5.
* Mail : [email protected]
* Description: 网络库的入口
*/
public class HttpUtil {
private Builder mBuilder;
private static final String GET = "get";
private static final String POST = "post";
private static final String PUT = "put";
private static final String DELETE = "delete";
private Dialog mDialog;
public HttpUtil(Builder builder) {
this.mBuilder = builder;
}
public void get(@NonNull final OnResponseResultCallBack mOnResponseResultCallBack) {
mBuilder.method(GET);
request(mOnResponseResultCallBack);
}
public void post(@NonNull final OnResponseResultCallBack mOnResponseResultCallBack) {
mBuilder.method(POST);
request(mOnResponseResultCallBack);
}
public void request(@NonNull final OnResponseResultCallBack mOnResponseResultCallBack) {
if (!NetworkUtil.isAvailable(SimpleApplication.getContent())) {
ToastUtils.showShort("网络不可用,请检查您的网络状态!");
mOnResponseResultCallBack.onError("网络不可用,请检查您的网络状态!");
return;
}
RequestParams params = new RequestParams(mBuilder.url);
Map paramsHeader = mBuilder.header;
Map paramsMap = mBuilder.params;
Map paramsFile = mBuilder.files;
for (Map.Entry entry : paramsMap.entrySet()) {
if (entry.getKey() != null) {
params.addBodyParameter(entry.getKey(), entry.getValue());
}
}
for (Map.Entry entry : paramsHeader.entrySet()) {
if (entry.getKey() != null) {
params.addHeader(entry.getKey(), entry.getValue());
}
}
if (paramsFile.size() != 0) {
params.setMultipart(true);
}
for (Map.Entry entry : paramsFile.entrySet()) {
if (entry.getKey() != null) {
params.addBodyParameter(entry.getKey(), entry.getValue());
}
}
if (TextUtils.isEmpty(mBuilder.method)) {
LogUtil.d("请设置请求方式");
return;
}
HttpMethod method1 = HttpMethod.GET;
switch (mBuilder.method) {
case HttpUtil.GET:
method1 = HttpMethod.GET;
break;
case HttpUtil.DELETE:
method1 = HttpMethod.DELETE;
break;
case HttpUtil.POST:
method1 = HttpMethod.POST;
break;
case HttpUtil.PUT:
method1 = HttpMethod.PUT;
break;
}
if (mBuilder.context != null && mBuilder.isShowLoading) {
Handler mainHandler = new Handler(Looper.getMainLooper());
mainHandler.post(new Runnable() {
@Override
public void run() {
//已在主线程中,可以更新UI
mDialog = DialogUtil.createLoadingDialog(mBuilder.context);
mDialog.show();
}
});
}
//我这里用的是xutil3,以后可以替换成任何需要的网络库,只需改下就好了
thirdNetLib(mOnResponseResultCallBack, params, method1);
}
private void thirdNetLib(@NonNull final OnResponseResultCallBack mOnResponseResultCallBack, RequestParams params, HttpMethod method1) {
x.http().request(method1, params, new Callback.CacheCallback() {
private String result;
@Override
public void onSuccess(String result) {
this.result = result;
}
@Override
public void onError(Throwable ex, boolean isOnCallback) {
if (!TextUtils.isEmpty(ex.getMessage())) {
LogUtil.d(ex.getMessage());
mOnResponseResultCallBack.onError(ex.getMessage());
}
if (mDialog != null) {
mDialog.dismiss();
}
}
@Override
public void onCancelled(CancelledException cex) {
if (!TextUtils.isEmpty(cex.getMessage())) {
LogUtil.d("cex:" + cex.getMessage());
mOnResponseResultCallBack.onError(cex.getMessage());
}
if (mDialog != null) {
mDialog.dismiss();
}
}
@Override
public void onFinished() {
mOnResponseResultCallBack.onSuccess(result);
if (mBuilder.context != null) {
if (mDialog != null) {
mDialog.dismiss();
}
}
}
@Override
public boolean onCache(String result) {
this.result = result;
return false;
}
});
}
public interface OnResponseResultCallBack {
void onSuccess(String result);
void onError(String errMessage);
}
public static final class Builder {
private String url;
private String method;
private Context context;
private boolean isShowLoading = true;
private Map header = new ArrayMap<>();
private Map params = new ArrayMap<>();
private Map files = new ArrayMap<>();
public Builder(Context context) {
this.context = context;
}
// public Builder context(Context context) {
// this.context = context;
// return this;
// }
public Builder isShowLoading(boolean isShowLoading) {
this.isShowLoading = isShowLoading;
return this;
}
public Builder url(String url) {
this.url = url;
return this;
}
public Builder method(String method) {
this.method = method;
return this;
}
public Builder header(String key, String value) {
header.put(key, value);
return this;
}
public Builder param(String key, String value) {
params.put(key, value);
return this;
}
public Builder file(String key, File file) {
files.put(key, file);
return this;
}
public HttpUtil build() {
return new HttpUtil(this);
}
}
}