关于介绍的可以先看这篇文章,OkHttp3使用介绍
本次封装要实现的功能有:
1.缓存添加,删除
2.请求参数封装
3.请求头封装
4.响应结果封装
5.回调线程处理
6.请求方式设置
7.响应结果类型设置
8.支持使用自签名证书
9.下载进度监听
10.上传进度监听
使用方式介绍
在Application中进行全局初始化
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
//初始化HttpManager
new HttpManager.Builder(this).build();
}
}
异步get请求
private void demo22() {
String url = "http://192.168.30.217/shopping/test/demo1";
HttpManager.getInstance().getJson(url, new HttpManager.ResultCallback() {
@Override
public void onFailure(Exception e) {
System.out.println("onFailure:" + e.getMessage());
}
@Override
public void onSuccess(Object o, HttpManager.Result result) throws Exception {
System.out.println(result.getJson());
}
});
}
异步post请求
private void demo12() {
Map<String, String> headerMap = new HashMap<>();
headerMap.put("Cookie", "session=123123");
Map<String, String> bodyMap = new HashMap();
bodyMap.put("username", "胜哥");
bodyMap.put("age", "20");
bodyMap.put("hobby", "吃,喝,玩");
String url = "http://192.168.30.217/shopping/test/demo1";
HttpManager.getInstance().postJson(url, headerMap, bodyMap,
new HttpManager.ResultCallback(this) {
@Override
public void onFailure(Exception e) {
System.out.println("onFailure:" + e.getMessage());
}
@Override
public Object doInBackground(HttpManager.Result result) throws Exception {
return result.getJson().optJSONObject("user");
}
@Override
public void onSuccess(Object o, HttpManager.Result result) throws Exception {
System.out.println("o=" + o + " result:" + result.getJson());
}
});
}
异步上传文件
支持批量上传
private void demo13() {
Map<String, String> headerMap = new HashMap<>();
headerMap.put("Cookie", "session=123123");
Map<String, String> bodyMap = new HashMap();
bodyMap.put("username", "胜哥");
bodyMap.put("age", "20");
bodyMap.put("hobby", "吃,喝,玩");
File f1 = createFile("c.mp4");
File f2 = createFile("timg.gif");
List<File> file = new ArrayList<>();
file.add(f1);
file.add(f2);
String url = "http://192.168.30.217/shopping/test/demo1";
HttpManager.getInstance().postFile(url, "mulitupload", file,
headerMap, bodyMap, HttpManager.ResponseType.JSON,
new HttpManager.Progress() {
@Override
public void onProgress(long currByte, long totalByte, int progress) {
//上传进度监听
System.out.println("currByte:" + currByte + " totalByte:" + totalByte +
" progress:" + progress);
}
}, new HttpManager.ResultCallback() {
@Override
public void onFailure(Exception e) {
System.out.println("onFailure:" + e.getMessage());
}
@Override
public void onSuccess(Object o, HttpManager.Result result) throws Exception {
System.out.println(result.getJson());
}
});
}
异步文件下载
private void demo21() {
String url = "http://192.168.30.217/shopping/test/download?fileName=c.mp4";
HttpManager.getInstance().download(url, null, null,
new HttpManager.Progress() {
@Override
public void onProgress(long currByte, long totalByte, int progress) {
System.out.println("currByte:" + currByte + " totalByte:" + totalByte
+ " progress:" + progress);
if (progress == 100) {
System.out.println("下载完成!!");
}
}
}, new HttpManager.ResultCallback() {
@Override
public void onFailure(Exception e) {
System.out.println("onFailure:" + e.getMessage());
}
@Override
public void onSuccess(Object o, HttpManager.Result result) throws Exception {
copyFile(filename, result.getInputStream());
}
});
}
/**
* 保存下载的文件
*
* @param filename
* @param inputStream
* @throws IOException
*/
private void copyFile(String filename, InputStream inputStream) throws IOException {
File saveDir;
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
saveDir = new File(getExternalCacheDir(), "download");
} else {
saveDir = new File(getCacheDir(), "download");
}
if (!saveDir.exists()) {
saveDir.mkdirs();
}
String suffix = filename.substring(filename.lastIndexOf("."));
File saveFile = new File(saveDir, System.currentTimeMillis() + suffix);
BufferedInputStream bis = new BufferedInputStream(inputStream);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(saveFile));
int b;
while ((b = bis.read()) != -1) {
bos.write(b);
}
bos.flush();
bos.close();
bis.close();
}
同步get请求
private void demo23() {
new Thread(new Runnable() {
@Override
public void run() {
String url = "http://192.168.30.217/shopping/test/demo1";
HttpManager.Result result = HttpManager.getInstance().getJson(url);
System.out.println("返回结果" + result.getJson());
}
}).start();
}
同步post请求
private void demo24() {
new Thread(new Runnable() {
@Override
public void run() {
String url = "http://192.168.30.217/shopping/test/demo1";
Map<String, String> headerMap = new HashMap<>();
headerMap.put("Cookie", "session=123123");
Map<String, String> bodyMap = new HashMap();
bodyMap.put("username", "胜哥");
bodyMap.put("age", "20");
bodyMap.put("hobby", "吃,喝,玩");
HttpManager.Result result = HttpManager.getInstance().postJson(url,headerMap,bodyMap);
System.out.println("返回结果" + result.getJson());
}
}).start();
}
同步下载的文件
private void demo25() {
new Thread(new Runnable() {
@Override
public void run() {
String filename = "c.mp4";
String url = "http://192.168.30.217/shopping/test/download?fileName=" + filename;
HttpManager.Result result = HttpManager.getInstance().download(url,
null, null,
new HttpManager.Progress() {
@Override
public void onProgress(long currByte, long totalByte, int progress) {
System.out.println("currByte:" + currByte + " totalByte:" + totalByte +
" progress:" + progress);
if (progress == 100) {
System.out.println("下载完成!!");
}
}
});
try {
copyFile(filename, result.getInputStream());
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
同步上传文件
private void demo26() {
new Thread(new Runnable() {
@Override
public void run() {
Map<String, String> headerMap = new HashMap<>();
headerMap.put("Cookie", "session=123123");
Map<String, String> bodyMap = new HashMap();
bodyMap.put("username", "胜哥");
bodyMap.put("age", "20");
bodyMap.put("hobby", "吃,喝,玩");
File f1 = createFile("c.mp4");
File f2 = createFile("timg.gif");
List<File> file = new ArrayList<>();
file.add(f1);
file.add(f2);
String url = "http://192.168.30.217/shopping/test/demo1";
HttpManager.Result result = HttpManager.getInstance().postFile(url, "mulitupload",
file, headerMap, bodyMap, HttpManager.ResponseType.JSON,
new HttpManager.Progress() {
@Override
public void onProgress(long currByte, long totalByte, int progress) {
System.out.println("currByte:" + currByte + " totalByte:" + totalByte +
" progress:" + progress);
if (progress == 100) {
System.out.println("上传完成!!");
}
}
});
System.out.println("返回结果" + result.getJson());
}
}).start();
}
库的封装
下面介绍okhttp3的封装过程
从HttpManager的初始化入手,这里我使用Builder的方式来初始化,Builder是一个内部类
/**
* Builder类,用于初始化HttpManager
*/
public static class Builder {
private File cacheDir; //缓存路径
private long cacheSize = CACHE_SIZE;//缓存大小
private long readTimeout = 20;//读取的超时时间
private long writeTimeout = 20;//写入的超时时间
private long connectTimeout = 15;//连接的超时时间
private Application context; //上下文
private SSLSocketFactory sslSocketFactory;//https连接验证工厂
public Builder(Application application) {
this.context = application;
}
public Builder setCacheSize(long cacheSize) {
this.cacheSize = cacheSize;
return this;
}
public Builder setCacheDir(File cacheDir) {
this.cacheDir = cacheDir;
return this;
}
public Builder setReadTimeout(long readTimeout) {
this.readTimeout = readTimeout;
return this;
}
public Builder setWriteTimeout(long writeTimeout) {
this.writeTimeout = writeTimeout;
return this;
}
public Builder setConnectTimeout(long connectTimeout) {
this.connectTimeout = connectTimeout;
return this;
}
//设置受信任的证书
public Builder setCertificates(InputStream... certificates) {
try {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
int index = 0;
for (InputStream certificate : certificates) {
String certificateAlias = Integer.toString(index++);
keyStore.setCertificateEntry(certificateAlias,
certificateFactory.generateCertificate(certificate));
try {
if (certificate != null)
certificate.close();
} catch (IOException e) {
}
}
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManagerFactory trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
sslContext.init(
null,
trustManagerFactory.getTrustManagers(),
new SecureRandom()
);
this.sslSocketFactory = sslContext.getSocketFactory();
} catch (Exception e) {
e.printStackTrace();
}
return this;
}
public HttpManager build() {
if (this.cacheDir == null) {
this.cacheDir = createCacheDir(this.context);
}
return mInstance = new HttpManager(cacheDir, cacheSize, connectTimeout,
readTimeout, writeTimeout, sslSocketFactory);
}
}
接着是在HttpManager的构造方法中对OkHttpClient进行全局初始化
public class HttpManager {
private static volatile HttpManager mInstance;
private static final long CACHE_SIZE = 10 * 1024 * 1024;//缓存区大小
private static Cache cache;
private OkHttpClient mClient;
/**
* 构造方法初始化OkHttpClient
*
* @param cacheDir
* @param cacheSize
* @param connectTimeout
* @param readTimeout
* @param writeTimeout
* @param sslSocketFactory
*/
private HttpManager( File cacheDir, long cacheSize, long connectTimeout, long readTimeout,
long writeTimeout, SSLSocketFactory sslSocketFactory) {
//初始化OkHttpClient.Builder
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.cache(cache = new Cache(cacheDir, cacheSize))
.connectTimeout(connectTimeout, TimeUnit.SECONDS)
.readTimeout(readTimeout, TimeUnit.SECONDS)
.writeTimeout(writeTimeout, TimeUnit.SECONDS);
X509TrustManager x509TrustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
//校验客户端证书,不做处理就是接受任意客户端证书
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
//校验服务器端证书,不做处理就是接受任意服务端证书
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
};
if (null != sslSocketFactory) {
//使用自签名证书验证
//如果访问的不是自签名的网站就会报这个异常:
// java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
builder.sslSocketFactory(sslSocketFactory, x509TrustManager)
.hostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
} else {
//信任所有证书
builder.sslSocketFactory(getDefaultSslSocketFactory(x509TrustManager), x509TrustManager)
.hostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
}
mClient = builder.build();
}
public SSLSocketFactory getDefaultSslSocketFactory(X509TrustManager x509TrustManager) {
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{x509TrustManager}, null);
return sslContext.getSocketFactory();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
接着是提供HttpManager获取实例的方法
/**
* 获取实例
*
* @return
*/
public static HttpManager getInstance() {
//获取实例时,如果缓存被清空了,需要重新初始化
if (cache != null && cache.isClosed()) {
try {
//重新初始化cache
cache.initialize();
} catch (IOException e) {
e.printStackTrace();
}
}
return mInstance;
}
操作缓存的方法
/**
* 创建缓存目录
*
* @param context
* @return
*/
private static File createCacheDir(Context context) {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
return new File(context.getExternalCacheDir(), "okCache");
} else {
return new File(context.getCacheDir(), "okCache");
}
}
/**
* 清空缓存
*
* @param context
*/
public static void deleteCache(Context context) {
if (cache != null) {
try {
cache.delete();
cache = new Cache(createCacheDir(context), CACHE_SIZE);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 根据url获取缓存文件
*
* @param url
* @return
*/
public static File getCache(String url) {
if (url == null) throw new NullPointerException("url == null");
return new File(cache.directory(), okhttp3.Cache.key(HttpUrl.parse(url)) + ".1");
}
请求方式、请求类型、响应类型都是通过枚举方式事先定义好
//请求方式
public enum RequestMethod {
GET, POST
}
//请求类型,强制网络,强制缓存,网络优先
public enum RequestType {
FORCE_NETWORK, FORCE_CACHE, NETWORK_FIRST
}
//响应类型,json,字符串,流,字节数组
public enum ResponseType {
JSON, STRING, IO, BYTES
}
响应结果的封装
/**
* 结果封装
*/
public static class Result {
private String content;//结果类型是字符串时返回
private Map<String, List<String>> headers;//响应头
private int code;//响应状态码
private InputStream inputStream;//结果类型是流时返回
private byte[] bytes;//结果类型是字节数组时返回
private int resultType;//结果来自网络还是缓存
private String url;//请求的url
private JSONObject json;//结果类型是json时返回
public static final int TYPE_NETWORK = 0;//来自网络
public static final int TYPE_CACHE = 1;//来自缓存
public Result(ResponseType responseType, Response response) throws Exception {
if (null != response) {
this.url = response.request().url().toString();
this.code = response.code();
this.headers = response.headers().toMultimap();
this.resultType = response.networkResponse() != null ? TYPE_NETWORK : TYPE_CACHE;
if (null != response.body()) {
switch (responseType) {
case JSON:
this.json = new JSONObject(response.body().string());
break;
case STRING:
this.content = response.body().string();
break;
case IO:
this.inputStream = response.body().byteStream();
break;
case BYTES:
this.bytes = response.body().bytes();
break;
default:
this.content = response.body().string();
break;
}
}
}
}
public String getContent() {
return content;
}
public Map<String, List<String>> getHeaders() {
return headers;
}
public int getCode() {
return code;
}
public InputStream getInputStream() {
return inputStream;
}
public byte[] getBytes() {
return bytes;
}
public int getResultType() {
return resultType;
}
public String getUrl() {
return url;
}
public JSONObject getJson() {
return json;
}
}
响应结果的回调在UI线程的内部类
/**
* 结果处理,让结果回调在主线程
*/
public abstract static class ResultCallback {
final int MSG_SUCCESS = 0;//成功
final int MSG_FAILURE = -1;//失败
WeakReference<Context> context;//发起请求时的上下文,可选,处理请求的页面结束后,不回调结果
//在UI线程中处理回调
Handler mHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
if (msg.what == MSG_FAILURE) {
onFailure((Exception) msg.obj);
} else if (msg.what == MSG_SUCCESS) {
Object[] obj = (Object[]) msg.obj;
try {
onSuccess(obj[0], (Result) obj[1]);
} catch (Exception e) {
onFailure(e);
}
}
return true;
}
});
public ResultCallback() {
}
public ResultCallback(Context ctx) {
this.context = new WeakReference<Context>(ctx);
}
public final void onError(Exception e) {
if (!checkContext()) {
mHandler.removeCallbacksAndMessages(null);
return;
}
mHandler.sendMessage(mHandler.obtainMessage(MSG_FAILURE, e));
}
public final void onResponse(ResponseType responseType, Response response) throws IOException {
if (!checkContext()) {
mHandler.removeCallbacksAndMessages(null);
return;
}
try {
//子线程中运行,封装结果
Result result = new Result(responseType, response);
Object o = doInBackground(result);//回调子线程方法,有需要的可以重写该方法
mHandler.sendMessage(mHandler.obtainMessage(MSG_SUCCESS, new Object[]{o, result}));
} catch (Exception e) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_FAILURE, e));
}
}
/**
* 如果有传context,那么判断context是否有效,如果无效则不需要回调结果了
*
* @return
*/
private boolean checkContext() {
if (null != this.context && null != context.get()) {
Context ctx = context.get();
while (ctx instanceof ContextWrapper) {
ctx = ((ContextWrapper) ctx).getBaseContext();
if (ctx instanceof Activity) {
Activity activity = (Activity) ctx;
if (activity.isFinishing() || activity.isDestroyed()) {
return false;
}
}
}
if (ctx == null) {
return false;
}
}
return true;
}
//处理在子线程中
public Object doInBackground(Result result) throws Exception {
return null;
}
//处理在UI线程中,失败回调
public abstract void onFailure(Exception e);
//处理在UI线程中,成功回调
public abstract void onSuccess(Object o, Result result) throws Exception;
}
添加请求或者响应进度的回调内部类
/**
* 响应/请求 监听
*/
public abstract static class Progress {
public long startIndex() {
//初始响应的位置
return 0;
}
public boolean returnOnMainThread() {
//在主线程中返回
return true;
}
/**
* 持续进度显示
*
* @param currByte 当前读/写字节数
* @param totalByte 总字节数
* @param progress 响应进度0~100
*/
public abstract void onProgress(long currByte, long totalByte, int progress);
}
处理UI线程回调进度的Handler内部类
private static class UIHandler extends Handler {
Progress mProgress;
public UIHandler(Progress progress) {
super(Looper.getMainLooper());
this.mProgress = progress;
}
@Override
public void handleMessage(Message msg) {
if (msg.what == 200 && null != mProgress) {
long[] obj = (long[]) msg.obj;
mProgress.onProgress(obj[0], obj[1], (int) obj[2]);
}
}
}
处理响应进度的内部类,通过装饰者模式对ResponseBody进行增强,用于处理文件的下载进度获取
private class ProgressResponseBody extends ResponseBody {
private Progress mProgress;
private ResponseBody mResponseBody;
private Handler mHandler;
public ProgressResponseBody(ResponseBody responseBody, Progress progress) {
this.mProgress = progress;
this.mResponseBody = responseBody;
this.mHandler = new UIHandler(mProgress);
}
@Override
public MediaType contentType() {
return mResponseBody.contentType();
}
@Override
public long contentLength() {
return mResponseBody.contentLength();
}
@Override
public BufferedSource source() {
return Okio.buffer(new ForwardingSource(mResponseBody.source()) {
//总读取字节数
long totalBytesRead = 0L;
@Override
public long read(Buffer sink, long byteCount) throws IOException {
//当前已读字节数,若已读完则返回-1
long bytesRead = super.read(sink, byteCount);
if (mProgress != null) {
totalBytesRead += bytesRead == -1 ? 0 : bytesRead;
long curr = totalBytesRead + mProgress.startIndex();//如果有开始位置,则加上开始位置
int progress = (int) (curr * 100 / contentLength());
if (mProgress.returnOnMainThread()) {
//将结果发送到UI线程中
long[] obj = new long[]{curr, contentLength(), progress};
mHandler.sendMessage(mHandler.obtainMessage(200, obj));
} else {
//结果保持在子线程中回调
mProgress.onProgress(curr, contentLength(), progress);
}
}
return bytesRead;
}
});
}
}
处理请求进度的内部类,通过装饰者模式对RequestBody进行增强,用于处理文件的上传进度获取
private class ProgressRequestBody extends RequestBody {
private RequestBody mRequestBody;
private long totalByte;
private Handler mHandler;
private Progress mProgress;
public ProgressRequestBody(RequestBody requestBody, Progress progress) {
this.mRequestBody = requestBody;
this.mProgress = progress;
this.mHandler = new UIHandler(mProgress);
if (mRequestBody instanceof MultipartBody) {
MultipartBody multipartBody = (MultipartBody) mRequestBody;
for (MultipartBody.Part part : multipartBody.parts()) {
if (null != part.body().contentType()) { //普通参数设置是没有contentType的
try {
totalByte += part.body().contentLength();//累计总提交的文件大小
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
@Override
public MediaType contentType() {
return mRequestBody.contentType();
}
//包装完成的BufferedSink
private BufferedSink bufferedSink;
@Override
public void writeTo(BufferedSink sink) throws IOException {
if (bufferedSink == null) {
//包装
bufferedSink = Okio.buffer(new ForwardingSink(sink) {
//当前写入字节数
long bytesWritten = 0L;
@Override
public void write(Buffer source, long byteCount) throws IOException {
super.write(source, byteCount);
if (null != mProgress) {
//增加当前写入的字节数
bytesWritten += byteCount;
/**
* 回调,最终bytesWritten肯定是大于totalByte的,查看源码可知输出的内容还包括其他的
* 例如请求头数据,请求参数等等
*/
if (bytesWritten > totalByte) {
bytesWritten = totalByte;
}
int progress = (int) (bytesWritten * 100 / totalByte);
if (mProgress.returnOnMainThread()) {
//将结果发送到UI线程中
long[] obj = new long[]{bytesWritten, totalByte, progress};
mHandler.sendMessage(mHandler.obtainMessage(200, obj));
} else {
//结果保持在子线程中回调
mProgress.onProgress(bytesWritten, totalByte, progress);
}
}
}
});
}
//写入
mRequestBody.writeTo(bufferedSink);
//必须调用flush,否则最后一部分数据可能不会被写入
bufferedSink.flush();
}
}
下面是HttpManager 异步请求的总入口方法
/**
* GET/POST异步请求
*
* @param url 请求url
* @param file 上传的文件
* @param fileName 上传文件表单的name属性名称
* @param headerMap 请求头
* @param bodyMap 请求参数
* @param method 请求方式
* @param requestType 请求类型
* @param responseType 响应数据类型
* @param progress 响应进度,用于下载文件时的进度监听
* @param callback 回调结果
*/
public void asyncRequest(String url, String fileName, List<File> file,
Map<String, String> headerMap, Map<String, String> bodyMap,
RequestMethod method, RequestType requestType,
ResponseType responseType, Progress progress, ResultCallback callback) {
if (mClient == null) {
throw new RuntimeException("HttpManager must be initialized");
}
if (null != file) {
//上传文件请求
doRequest(initRequest(url, fileName, file, headerMap, bodyMap,
RequestMethod.POST, progress), RequestType.FORCE_NETWORK, responseType,
null, true, callback);
} else {
//其他请求
doRequest(initRequest(url, null, null, headerMap,
bodyMap, method, null), requestType, responseType, progress, true, callback);
}
}
同步请求总入口方法
/**
* GET/POST同步请求
*
* @param url
* @param fileName
* @param file
* @param headerMap
* @param bodyMap
* @param method
* @param requestType
* @param responseType
* @param progress
* @return Result
*/
public Result syncRequest(String url, String fileName, List<File> file,
Map<String, String> headerMap, Map<String, String> bodyMap,
RequestMethod method, RequestType requestType,
ResponseType responseType, Progress progress) {
if (mClient == null) {
throw new RuntimeException("HttpManager must be initialized");
}
if (null != file) {
//上传文件请求
return doRequest(initRequest(url, fileName, file, headerMap, bodyMap,
RequestMethod.POST, progress), RequestType.FORCE_NETWORK, responseType,
null, false, null);
} else {
//其他请求
return doRequest(initRequest(url, null, null, headerMap,
bodyMap, method, null), requestType, responseType, progress,
false, null);
}
}
initRequest 方法初始化请求
//初始化请求
private Request.Builder initRequest(String url, String fileName, List<File> file,
Map<String, String> headerMap, Map<String, String> bodyMap,
RequestMethod method, Progress progress) {
//构建请求
Request.Builder requestBuilder = new Request.Builder();
if (method == RequestMethod.GET) {
url = attachGetParams(url, bodyMap);//get请求参数拼接
requestBuilder.get();
} else {
//添加post请求参数封装
if (null != file && file.size() > 0) {
if (TextUtils.isEmpty(fileName)) {
throw new IllegalArgumentException("文件上传表单的name不能为空");
}
//文件上传表单数据封装
MultipartBody.Builder form = new MultipartBody.Builder();
form.setType(MultipartBody.FORM);//支持文件上传的表单格式
//循环封装File参数
for (File f : file) {
MediaType mediaType = MediaType.parse("text/x-markdown;charset=utf-8");
RequestBody fileBody = RequestBody.create(mediaType, f);
form.addFormDataPart(fileName, f.getName(), fileBody);//上传文件
}
//上传普通参数
if (null != bodyMap) {
for (String key : bodyMap.keySet()) {
form.addFormDataPart(key, bodyMap.get(key));
}
}
requestBuilder.post(new ProgressRequestBody(form.build(), progress));
} else {
//普通表单数据封装
if (null != bodyMap) {
FormBody.Builder form = new FormBody.Builder();
for (String key : bodyMap.keySet()) {
form.add(key, bodyMap.get(key));
}
requestBuilder.post(form.build());
}
}
}
//请求url和tag设置
requestBuilder.url(url).tag(url);
//请求头设置
if (null != headerMap) {
for (String key : headerMap.keySet()) {
requestBuilder.header(key, headerMap.get(key));
}
}
return requestBuilder;
}
doRequest发起请求
/**
* 发起请求
* @param requestBuilder
* @param requestType
* @param responseType
* @param progress
* @param async true 异步,false 同步
* @param callback 异步结果回调
* @return Result 同步结果返回
*/
private Result doRequest(final Request.Builder requestBuilder, final RequestType requestType,
final ResponseType responseType, final Progress progress,
boolean async, final ResultCallback callback) {
//设置缓存类型
switch (requestType) {
case FORCE_CACHE:
requestBuilder.cacheControl(CacheControl.FORCE_CACHE);
break;
case FORCE_NETWORK:
case NETWORK_FIRST:
default:
requestBuilder.cacheControl(CacheControl.FORCE_NETWORK);
break;
}
//监听响应进度,一般用于文件下载进度监听
final OkHttpClient client = mClient.newBuilder()
.addNetworkInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
//获取原始Response
Response originalResponse = chain.proceed(chain.request());
//返回新的Response
return originalResponse.newBuilder()
.body(new ProgressResponseBody(originalResponse.body(), progress))
.build();
}
})
.build();
//异步请求回调
Callback asynCallback = new Callback() {
int count;//请求失败的回调次数
@Override
public void onFailure(Call call, IOException e) {
if (count == 0) {
//网络优先失败,则请求缓存
if (requestType == RequestType.NETWORK_FIRST) {
count++;
Request request = requestBuilder.cacheControl(CacheControl.FORCE_CACHE).build();
client.newCall(request).enqueue(this);
} else {
if (null != callback)
callback.onError(e);
}
} else {
//第二次请求缓存也失败,这直接回调
if (null != callback)
callback.onError(e);
}
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (null != response && response.isSuccessful() && response.body() != null) {
if (null != callback)
callback.onResponse(responseType, response);
} else {
if (null != callback)
callback.onError(new Exception("Response is null"));
}
}
};
if (async) {
client.newCall(requestBuilder.build()).enqueue(asynCallback);
} else {
//同步请求
try {
Response response = client.newCall(requestBuilder.build()).execute();
if (null == response || !response.isSuccessful() || response.body() == null) {
if (requestType == RequestType.NETWORK_FIRST) {
//网络优先失败,则请求缓存
Request request = requestBuilder.cacheControl(CacheControl.FORCE_CACHE).build();
response = client.newCall(request).execute();
}
}
return new Result(responseType, response);
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
下面是几个重载的请求方法
/**
* 异步get请求,获取json数据
* @param url
* @param callback
*/
public void getJson(String url, ResultCallback callback) {
getJson(url, null, null, callback);
}
/**
* 异步get请求,获取json数据
*
* @param url
* @param headerMap
* @param bodyMap
* @param callback
*/
public void getJson(String url, Map<String, String> headerMap, Map<String, String> bodyMap,
ResultCallback callback) {
asyncRequest(url, null, null, headerMap, bodyMap, RequestMethod.GET,
RequestType.NETWORK_FIRST, ResponseType.JSON, null, callback);
}
/**
* 异步POST请求,获取json数据
*
* @param url
* @param headerMap
* @param bodyMap
* @param callback
*/
public void postJson(String url, Map<String, String> headerMap, Map<String, String> bodyMap,
ResultCallback callback) {
asyncRequest(url, null, null, headerMap, bodyMap, RequestMethod.POST,
RequestType.FORCE_NETWORK, ResponseType.JSON, null, callback);
}
/**
* 异步下载文件
*
* @param url
* @param headerMap
* @param bodyMap
* @param progress 下载监听
* @param callback
*/
public void download(String url, Map<String, String> headerMap, Map<String, String> bodyMap,
Progress progress, ResultCallback callback) {
asyncRequest(url, null, null, headerMap, bodyMap, RequestMethod.GET,
RequestType.FORCE_NETWORK, ResponseType.IO, progress, callback);
}
/**
* 异步异步上传文件
*
* @param url 请求url
* @param file 上传的文件
* @param fileName 上传文件表单的name属性名称
* @param headerMap 请求头
* @param bodyMap 请求参数
* @param responseType 响应类型
* @param progress 上传进度监听
* @param callback 回调结果
*/
public void postFile(String url, String fileName, List<File> file, Map<String, String> headerMap,
Map<String, String> bodyMap, ResponseType responseType, Progress progress,
ResultCallback callback) {
asyncRequest(url, fileName, file, headerMap, bodyMap, null, null,
responseType, progress, callback);
}
/**
* 同步get请求
* @param url
* @return
*/
public Result getJson(String url) {
return getJson(url, null, null);
}
/**
* 同步get请求
*
* @param url
* @param headerMap
* @param bodyMap
* @return Result
*/
public Result getJson(String url, Map<String, String> headerMap, Map<String, String> bodyMap) {
return syncRequest(url, null, null, headerMap, bodyMap, RequestMethod.GET,
RequestType.NETWORK_FIRST, ResponseType.JSON, null);
}
/**
* 同步post请求
* @param url
* @param headerMap
* @param bodyMap
* @return Result
*/
public Result postJson(String url, Map<String, String> headerMap, Map<String, String> bodyMap) {
return syncRequest(url, null, null, headerMap, bodyMap, RequestMethod.POST,
RequestType.FORCE_NETWORK, ResponseType.JSON, null);
}
/**
* 同步下载文件
* @param url
* @param headerMap
* @param bodyMap
* @param progress 下载进度监听
* @return Result
*/
public Result download(String url, Map<String, String> headerMap, Map<String, String> bodyMap,
Progress progress) {
return syncRequest(url, null, null, headerMap, bodyMap, RequestMethod.GET,
RequestType.FORCE_NETWORK, ResponseType.IO, progress);
}
/**
* 同步提交文件
*
* @param url
* @param fileName
* @param file
* @param headerMap
* @param bodyMap
* @param responseType
* @param progress
* @return Result
*/
public Result postFile(String url, String fileName, List<File> file, Map<String, String> headerMap,
Map<String, String> bodyMap, ResponseType responseType, Progress progress) {
return syncRequest(url, fileName, file, headerMap, bodyMap, RequestMethod.POST,
RequestType.FORCE_NETWORK, responseType, progress);
}
搞定~~