文章目录
我们都知道,Retrofit目前是比较火的网络请求框架,本身就是是OKHttp进行了封装,实际干活的还是OKhttp,所以为了更好的用好Retrofit,很有必要复习一下OKHTTP,并且OKhttp的最新版本3.10.0和之前版本的操作也是不尽相同,所以今天重新对他操作一波,从简单实用到常用使用方式的封装均有涉猎,亲测可以正常使用,本文以豆瓣的电影api做测试数据,详细源码下方会有下载地址,时间紧迫,废话不多说,代码就是最好的注释,欢迎fork!
PS:本文主要围绕以下四个文件做操作:
OKHTTP3.10的GET请求
private void getDouBan1() {
//1,创建OKHttpClient对象
OkHttpClient okHttpClient = new OkHttpClient();
//2,创建一个Request
Request request = new Request.Builder().url(Constant.URL).build();
//3,创建一个call对象
Call call = okHttpClient.newCall(request);
//4,将请求添加到调度中
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) {
if (response.isSuccessful()) {
try {
res = response.body().string();
ThreadPoolUtil.execute(new Runnable() {
@Override
public void run() {
Log.d(TAG, res);
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
}
OKHTTP3.10的POST请求
private void postDouBan() {
//1,创建OKHttpClient对象
OkHttpClient okHttpClient = new OkHttpClient();
//2,创建一个Request
RequestBody requestBody = new FormBody.Builder()
.add("username", "ytf")
.add("password", "123")
.build();
Request request = new Request.Builder().url(Constant.URL).post(requestBody).build();
//4,将请求添加到调度中
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
try {
res = response.body().string();
ThreadPoolUtil.execute(new Runnable() {
@Override
public void run() {
// Looper.prepare();
// Toast.makeText(MainActivity.this, res, Toast.LENGTH_SHORT).show();
Log.d(TAG, res);
EventBus.getDefault().post(res);
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
}
RequestBody示例:
OKHTTP3.10的GET封装请求
工具类的单例:
/**
* 懒汉式加锁单例模式
* @return
*/
public OkHTTPManger() {
okHttpClient = new OkHttpClient();
}
public static OkHTTPManger getInstance() {
if (instance == null) {
synchronized (OkHTTPManger.class) {
if (instance == null) {
instance = new OkHTTPManger();
}
}
}
return instance;
}
get同步请求
/**
* get同步请求不需要传参数
* 通过response.body().string()获取返回的字符串
*
* @param url
* @return
*/
public String getSyncBackString(String url) {
Request request = new Request.Builder()
.url(url)
.build();
Call call = okHttpClient.newCall(request);
try {
Response response = call.execute();
// 将response转化成String
String responseStr = response.body().string();
return responseStr;
} catch (IOException e) {
Logger.e("GET同步请求解析为String异常" + e.toString());
e.printStackTrace();
}
return null;
}
/**
* get同步请求
* 通过response.body().bytes()获取返回的二进制字节数组
*
* @param url
* @return
*/
public byte[] getSyncBackByteArray(String url) {
Request request = new Request.Builder()
.url(url)
.build();
Call call = okHttpClient.newCall(request);
try {
Response response = call.execute();
// 将response转化成String
byte[] responseStr = response.body().bytes();
return responseStr;
} catch (IOException e) {
Logger.e("GET同步请求解析为byte数组异常" + e.toString());
e.printStackTrace();
}
return null;
}
/**
* get同步请求
* 通过response.body().byteStream()获取返回的二进制字节流
*
* @param url
* @return
*/
public InputStream getSyncBackByteStream(String url) {
Request request = new Request.Builder()
.url(url)
.build();
Call call = okHttpClient.newCall(request);
try {
Response response = call.execute();
// 将response转化成String
InputStream responseStr = response.body().byteStream();
return responseStr;
} catch (IOException e) {
Logger.e("GET同步请求解析为String异常" + e.toString());
e.printStackTrace();
}
return null;
}
/**
* get同步请求
* 通过response.body().byteStream()获取返回的二进制字节流
*
* @param url
* @return
*/
public Reader getSyncBackCharReader(String url) {
Request request = new Request.Builder()
.url(url)
.build();
Call call = okHttpClient.newCall(request);
try {
Response response = call.execute();
// 将response转化成String
Reader responseStr = response.body().charStream();
return responseStr;
} catch (IOException e) {
Logger.e("GET同步请求解析为Reader异常" + e.toString());
e.printStackTrace();
}
return null;
}
get异步请求
/**
* get异步请求不传参数
* 通过response.body().string()获取返回的字符串
* 异步返回值不能更新UI,要开启新线程
*
* @param url
* @return
*/
public String getAsynBackStringWithoutParms(String url, final MyDataCallBack myDataCallBack) {
final Request request = new Request.Builder()
.url(url)
.build();
Call call = okHttpClient.newCall(request);
try {
myDataCallBack.onBefore(request);
// 请求加入调度
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// Logger.e("GET异步请求为String失败"+e.toString());
myDataCallBack.requestFailure(request, e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
responseStrGETAsyn = response.body().string();
try {
myDataCallBack.requestSuccess(responseStrGETAsyn);
} catch (Exception e) {
e.printStackTrace();
Logger.e("GET异步请求为String解析异常失败" + e.toString());
}
}
});
myDataCallBack.onAfter();
} catch (Exception e) {
Logger.e("GET异步请求解析为String异常" + e.toString());
e.printStackTrace();
}
return responseStrGETAsyn;
}
/**
* get异步请求传参数(可以传null)
* 通过response.body().string()获取返回的字符串
* 异步返回值不能更新UI,要开启新线程
*
* @param url
* @return
*/
public String getAsynBackStringWithParms(String url, Map<String, String> params, final MyDataCallBack myDataCallBack) {
if (params == null) {
params = new HashMap<>();
}
// 请求url(baseUrl+参数)
String doUrl = urlJoint(url, params);
final Request request = new Request.Builder()
.url(doUrl)
// .header("Cookie", "自动管理更新需要携带的Cookie")
.build();
Call call = okHttpClient.newCall(request);
try {
myDataCallBack.onBefore(request);
// 请求加入调度
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// Logger.e("GET异步请求为String失败"+e.toString());
myDataCallBack.requestFailure(request, e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
responseStrGETAsyn = response.body().string();
try {
myDataCallBack.requestSuccess(responseStrGETAsyn);
} catch (Exception e) {
e.printStackTrace();
Logger.e("GET异步请求为String解析异常失败" + e.toString());
}
}
});
myDataCallBack.onAfter();
} catch (Exception e) {
Logger.e("GET异步请求解析为String异常" + e.toString());
e.printStackTrace();
}
return responseStrGETAsyn;
}
明文传参拼接URL
/**
* @param url 实际URL的path
* @param params
* @return
*/
private static String urlJoint(String url, Map<String, String> params) {
StringBuilder realURL = new StringBuilder(Constant.URL);
realURL = realURL.append(url);
boolean isFirst = true;
if (params == null) {
params = new HashMap<>();
} else {
Set<Map.Entry<String, String>> entrySet = params.entrySet();
for (Map.Entry<String, String> entry : entrySet) {
if (isFirst && !url.contains("?")) {
isFirst = false;
realURL.append("?");
} else {
realURL.append("&");
}
realURL.append(entry.getKey());
realURL.append("=");
if (entry.getValue() == null) {
realURL.append(" ");
} else {
realURL.append(entry.getValue());
}
}
}
return realURL.toString();
}
##OKHTTP3.10的POST封装请求
post异步请求map传参
/**
* post异步请求map传参
* 通过response.body().string()获取返回的字符串
* 异步返回值不能更新UI,要开启新线程
*
* @param url
* @return
*/
public String postAsynBackString(String url, Map<String, String> params, final MyDataCallBack myDataCallBack) {
RequestBody requestBody;
if (params == null) {
params = new HashMap<>();
}
FormBody.Builder builder = new FormBody.Builder();
/**
* 在这对添加的参数进行遍历
*/
addMapParmsToFromBody(params, builder);
requestBody = builder.build();
String realURL = urlJoint(url, null);
//结果返回
final Request request = new Request.Builder()
.url(realURL)
.post(requestBody)
.build();
Call call = okHttpClient.newCall(request);
try {
myDataCallBack.onBefore(request);
// 请求加入调度
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
myDataCallBack.requestFailure(request, e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
responseStrGETAsyn = response.body().string();//此处也可以解析为byte[],Reader,InputStream
try {
myDataCallBack.requestSuccess(responseStrGETAsyn);
} catch (Exception e) {
e.printStackTrace();
Logger.e("POST异步请求为String解析异常失败" + e.toString());
}
}
});
myDataCallBack.onAfter();
} catch (Exception e) {
Logger.e("POST异步请求解析为String异常" + e.toString());
e.printStackTrace();
}
return responseStrGETAsyn;
}
将参数添加到请求体
private void addMapParmsToFromBody(Map<String, String> params, FormBody.Builder builder) {
for (Map.Entry<String, String> map : params.entrySet()) {
String key = map.getKey();
String value;
/**
* 判断值是否是空的
*/
if (map.getValue() == null) {
value = "";
} else {
value = map.getValue();
}
/**
* 把key和value添加到formbody中
*/
builder.add(key, value);
}
}
post异步请求json传参
/**
* post异步请求json传参
* 通过response.body().string()获取返回的字符串
* 异步返回值不能更新UI,要开启新线程
*
* @param url
* @return
*/
public String postAsynRequireJson(String url, Map<String, String> params, final MyDataCallBack myDataCallBack) {
if (params == null) {
params = new HashMap<>();
}
// 将map转换成json,需要引入Gson包
String mapToJson = new Gson().toJson(params);
final String realURL = urlJoint(url, null);
final Request request = buildJsonPostRequest(realURL, mapToJson);
Call call = okHttpClient.newCall(request);
try {
myDataCallBack.onBefore(request);
// 请求加入调度
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
myDataCallBack.requestFailure(request, e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
responseStrGETAsyn = response.body().string();//此处也可以解析为byte[],Reader,InputStream
try {
myDataCallBack.requestSuccess(responseStrGETAsyn);
} catch (Exception e) {
e.printStackTrace();
Logger.e("POST异步请求为String解析异常失败" + e.toString());
}
}
});
myDataCallBack.onAfter();
} catch (Exception e) {
Logger.e("POST异步请求解析为String异常" + e.toString());
e.printStackTrace();
}
return responseStrGETAsyn;
}
效果图:
以json方式传入请求体
**
* Json_POST请求参数
*
* @param url url
* @param json json
* @return requestBody
*/
private Request buildJsonPostRequest(String url, String json) {
// RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
RequestBody requestBody = RequestBody.create(JSON, json);
return new Request.Builder().url(url).post(requestBody).build();
}
以String方式传入请求体
/**
* String_POST请求参数
*
* @param url url
* @param json json
* @return requestBody
*/
private Request buildStringPostRequest(String url, String json) {
RequestBody requestBody = RequestBody.create(MEDIA_TYPE_MARKDOWN, json);
return new Request.Builder().url(url).post(requestBody).build();
}
文件上传:
基于http的文件上传(传入文件名和key)
/**
* 基于http的文件上传(传入文件名和key)
* 通过addFormDataPart
*
* @param url URL的Path部分
* @param myDataCallBack 自定义回调接口
* 将file作为请求体传入到服务端.
* @param fileKey 文件传入服务器的键"image"
* @fileName: "pic.png"
*/
private void upLoadMultiFileSimple(String url, String fileName, String fileKey, final MyDataCallBack myDataCallBack) {
File file = new File(Environment.getExternalStorageDirectory(), fileName);
RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(fileKey, fileName, fileBody)
.build();
final String realURL = urlJoint(url, null);
final Request request = new Request.Builder()
.url(realURL)
.post(requestBody)
.build();
Call call = okHttpClient.newCall(request);
try {
myDataCallBack.onBefore(request);
// 请求加入调度
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
myDataCallBack.requestFailure(request, e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
try {
myDataCallBack.requestSuccess(responseStrGETAsyn);
} catch (Exception e) {
e.printStackTrace();
Logger.e("POST异步文件上传失败" + e.toString());
}
}
});
myDataCallBack.onAfter();
} catch (Exception e) {
Logger.e("POST异步文件上传异常" + e.toString());
e.printStackTrace();
}
}
基于http的文件上传,混合参数和文件请求
/**
* 基于http的文件上传(传入文件数组和key)混合参数和文件请求
* 通过addFormDataPart可以添加多个上传的文件
*
* @param url URL的Path部分
* @param myDataCallBack 自定义回调接口
* 将file作为请求体传入到服务端.
* @param files 上传的文件
* @param fileKeys 上传的文件key集合
*/
private void upLoadMultiFile(String url, File[] files, String[] fileKeys, Map<String, String> params, final MyDataCallBack myDataCallBack) {
if (params == null) {
params = new HashMap<>();
}
final String realURL = urlJoint(url, null);
FormBody.Builder builder = new FormBody.Builder();
addMapParmsToFromBody(params, builder);
RequestBody requestBody = builder.build();
MultipartBody.Builder multipartBody = new MultipartBody.Builder();
multipartBody.setType(MultipartBody.ALTERNATIVE)
.addPart(requestBody);
if (files != null) {
RequestBody fileBody = null;
for (int i = 0; i < files.length; i++) {
File file = files[i];
String fileName = file.getName();
fileBody = RequestBody.create(MediaType.parse(guessMimeType(fileName)), file);
//TODO 根据文件名设置contentType
multipartBody.addPart(Headers.of("Content-Disposition",
"form-data; name=\"" + fileKeys[i] + "\"; filename=\"" + fileName + "\""),
fileBody);
}
}
final Request request = new Request.Builder()
.url(realURL)
.post(multipartBody.build())
.build();
Call call = okHttpClient.newCall(request);
try {
myDataCallBack.onBefore(request);
// 请求加入调度
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
myDataCallBack.requestFailure(call.request(), e);
}
@Override
public void onResponse(Call call, Response response) {
try {
myDataCallBack.requestSuccess(response.body().string());
} catch (Exception e) {
e.printStackTrace();
Logger.e("POST异步文件上传失败" + e.toString());
}
}
});
myDataCallBack.onAfter();
} catch (Exception e) {
Logger.e("POST异步文件上传异常" + e.toString());
e.printStackTrace();
}
}
***************************************************************************************
private String guessMimeType(String fileName) {
FileNameMap fileNameMap = URLConnection.getFileNameMap();
String contentTypeFor = fileNameMap.getContentTypeFor(fileName);
if (contentTypeFor == null) {
contentTypeFor = "application/octet-stream";
}
return contentTypeFor;
}
文件下载
/**
* 文件下载
* @param url path路径
* @param destFileDir 本地存储的文件夹路径
* @param myDataCallBack 自定义回调接口
*/
private void downLoadFileAsyn(final String url, final String destFileDir, final MyDataCallBack myDataCallBack){
String realURL=urlJoint(url,null);
Request request=new Request.Builder()
.url(realURL)
.build();
Call call=okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
myDataCallBack.requestFailure(call.request(),e);
}
@Override
public void onResponse(Call call, Response response) {
InputStream is = null;
byte[] buf = new byte[2048];
int len = 0;
FileOutputStream fos = null;
is = response.body().byteStream();
File file = new File(destFileDir, getFileName(url));
try {
fos = new FileOutputStream(file);
while ((len = is.read(buf)) != -1)
{
fos.write(buf, 0, len);
}
fos.flush();
} catch (IOException e) {
Logger.e("文件下载异常:",e.getMessage());
e.printStackTrace();
}finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
Logger.e("文件流关闭异常:",e.getMessage());
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
Logger.e("文件流关闭异常:",e.getMessage());
e.printStackTrace();
}
}
}
//如果下载文件成功,第一个参数为文件的绝对路径
sendSuccessResultCallback(file.getAbsolutePath(), myDataCallBack);
myDataCallBack.requestSuccess(response.body().toString());
}
});
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
private String getFileName(String url) {
int separatorIndex = url.lastIndexOf("/");
return (separatorIndex < 0) ? url : url.substring(separatorIndex + 1, url.length());
}
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
private void sendSuccessResultCallback(final String absolutePath, final MyDataCallBack myDataCallBack) {
ThreadPoolUtil.execute(new Runnable() {
@Override
public void run() {
if (myDataCallBack!=null){
myDataCallBack.requestSuccess(absolutePath);
}
}
});
}
自定义CallBack回调MyDataCallBack
package com.app.ytf.httpdemo.okhttp;
import com.google.gson.internal.$Gson$Types;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import okhttp3.Request;
/**
* @author ytf
* 正常情况下多数返回的是string格式,
* 如果要接收返回其他类型的数据可以依照需求放开注释,
* 使用参照同步请求做法
*/
public abstract class MyDataCallBack<T> {
//请求数据的返回类型,包含常见的(Bean,List等)
Type mType;
public MyDataCallBack() {
// mType=getSuperclassTypeParameter(getClass());
}
/**
* 通过反射返回想要的类型
* @param subclass
* @return
*/
static Type getSuperclassTypeParameter(Class<?> subclass) {
Type superclass = subclass.getGenericSuperclass();
if (superclass instanceof Class) {
throw new RuntimeException("未知返回类型");
}
ParameterizedType parameterized = (ParameterizedType) superclass;
return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
}
/**
* 在请求之前的方法,一般用于加载进度框ProgressBar展示
*
* @param request
*/
public abstract void onBefore(Request request);
public abstract void requestSuccess(T result);
// void requestSuccess(Reader result) throws Exception;
// void requestSuccess(InputStream result) throws Exception;
// void requestSuccess(byte[] result) throws Exception;
public abstract void requestFailure(Request request, IOException e);
/**
* 在请求之后的方法,一般用于加载框隐藏
*/
public abstract void onAfter();
}
自定义日志拦截器
package com.app.ytf.httpdemo.okhttp;
import com.orhanobut.logger.Logger;
import java.io.IOException;
import java.util.Locale;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
/**
* @author ytf
* 自定义拦截器
* Chain 对象可以拿到当前请求的 Request 对象,然后我们可以对Request做二次处理,
* 最后生成我们需要的请求,然后再通过网络发送请求到服务端,这样就完成了一次拦截
*/
public class HeaderInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Logger.d(String.format("Sending request %s on %s%n%s", request.url(), chain.connection(), request.headers()));
long t1 = System.nanoTime();
okhttp3.Response response = chain.proceed(chain.request());
long t2 = System.nanoTime();
Logger.d(String.format(Locale.getDefault(), "Received response for %s in %.1fms%n%s",
response.request().url(), (t2 - t1) / 1e6d, response.headers()));
okhttp3.MediaType mediaType = response.body().contentType();
String content = response.body().string();
Logger.json(content);
Response response1=chain.proceed(request);
Logger.d("返回response:",response1.toString());
return response.newBuilder()
.header("Authorization", "请求头授权信息拦截")
.body(okhttp3.ResponseBody.create(mediaType, content))
.build();
}
}
自定义网络拦截器
package com.app.ytf.httpdemo.okhttp;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import com.app.ytf.httpdemo.APP;
import java.io.IOException;
import okhttp3.CacheControl;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
/**
* @author ytf
* 设置网络拦截器,实现在线和离线缓存
*/
public class CacheInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!isNetworkConnected()) {
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build();
}
Response originalResponse = chain.proceed(request);
if (isNetworkConnected()) {
//有网的时候读接口上的@Headers里的配置,你可以在这里进行统一的设置(注掉部分)
String cacheControl = request.cacheControl().toString();
return originalResponse.newBuilder()
.header("Cache-Control", cacheControl)
//.header("Cache-Control", "max-age=3600")
.removeHeader("Pragma") // 清除头信息,因为服务器如果不支持,会返回一些干扰信息,不清除下面无法生效
.build();
} else {
//1.不需要缓存:Cache-Control: no-cache或Cache-Control: max-age=0
//2.如果想先显示数据,在请求。(类似于微博等):Cache-Control: only-if-cached
int maxAge = 60 * 60;
return originalResponse.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-age=" + maxAge)
.removeHeader("Pragma")
.build();
}
}
/**
* 判断网络是否可用的方法
*
* @return
*/
private boolean isNetworkConnected() {
ConnectivityManager connectivity = (ConnectivityManager) APP.getInstance()
.getSystemService(Context.CONNECTIVITY_SERVICE);
if (null != connectivity) {
NetworkInfo info = connectivity.getActiveNetworkInfo();
if (null != info && info.isConnected()) {
if (info.getState() == NetworkInfo.State.CONNECTED) {
return true;
}
}
}
return false;
}
}
工具类详细代码:
package com.app.ytf.httpdemo.okhttp;
import android.os.Environment;
import com.app.ytf.httpdemo.APP;
import com.app.ytf.httpdemo.util.Constant;
import com.app.ytf.httpdemo.util.ThreadPoolUtil;
import com.google.gson.Gson;
import com.google.gson.internal.$Gson$Types;
import com.orhanobut.logger.Logger;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.ConnectException;
import java.net.FileNameMap;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.sql.ParameterMetaData;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import okhttp3.Cache;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.FormBody;
import okhttp3.Headers;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
/**
* @author ytf
*/
public class OkHTTPManger {
private static OkHttpClient okHttpClient;
private volatile static OkHTTPManger instance;//防止多个线程同时访问
//提交json数据
private static final MediaType JSON = MediaType.parse("application/json;charset=utf-8");
//提交字符串数据
private static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown;charset=utf-8");
private static String responseStrGETAsyn;
private final HashMap<String, List<Cookie>> cookieStore = new HashMap<>();
// 使用getCacheDir()来作为缓存文件的存放路径(/data/data/包名/cache) ,
// 如果你想看到缓存文件可以临时使用 getExternalCacheDir()(/sdcard/Android/data/包名/cache)。
private static File cacheFile;
private static Cache cache;
public OkHTTPManger() {
// if (APP.getInstance().getApplicationContext().getCacheDir()!=null){
// cacheFile = new File(APP.getInstance().getCacheDir(), "Test");
// cache = new Cache(cacheFile, 1024 * 1024 * 10);
// }
okHttpClient = new OkHttpClient();
okHttpClient.newBuilder()
// .addInterceptor(new HeaderInterceptor())
// .addNetworkInterceptor(new CacheInterceptor())
// .cache(cache)
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.cookieJar(new CookieJar() {
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
cookieStore.put(url.host(), cookies);
}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
List<Cookie> cookies = cookieStore.get(url.host());
return cookies != null ? cookies : new ArrayList<Cookie>();
//自动管理Cookie发送Request都不用管Cookie这个参数也不用去response获取新Cookie什么的了。还能通过cookieStore获取当前保存的Cookie。
}
});
}
/**
* 懒汉式加锁单例模式
* @return
*/
public static OkHTTPManger getInstance() {
if (instance == null) {
synchronized (OkHTTPManger.class) {
if (instance == null) {
instance = new OkHTTPManger();
}
}
}
return instance;
}
/**
* get同步请求不需要传参数
* 通过response.body().string()获取返回的字符串
*
* @param url
* @return
*/
public String getSyncBackString(String url) {
Request request = new Request.Builder()
.url(url)
.build();
Call call = okHttpClient.newCall(request);
try {
Response response = call.execute();
// 将response转化成String
String responseStr = response.body().string();
return responseStr;
} catch (IOException e) {
Logger.e("GET同步请求解析为String异常" + e.toString());
e.printStackTrace();
}
return null;
}
/**
* get同步请求
* 通过response.body().bytes()获取返回的二进制字节数组
*
* @param url
* @return
*/
public byte[] getSyncBackByteArray(String url) {
Request request = new Request.Builder()
.url(url)
.build();
Call call = okHttpClient.newCall(request);
try {
Response response = call.execute();
// 将response转化成String
byte[] responseStr = response.body().bytes();
return responseStr;
} catch (IOException e) {
Logger.e("GET同步请求解析为byte数组异常" + e.toString());
e.printStackTrace();
}
return null;
}
/**
* get同步请求
* 通过response.body().byteStream()获取返回的二进制字节流
*
* @param url
* @return
*/
public InputStream getSyncBackByteStream(String url) {
Request request = new Request.Builder()
.url(url)
.build();
Call call = okHttpClient.newCall(request);
try {
Response response = call.execute();
// 将response转化成String
InputStream responseStr = response.body().byteStream();
return responseStr;
} catch (IOException e) {
Logger.e("GET同步请求解析为String异常" + e.toString());
e.printStackTrace();
}
return null;
}
/**
* get同步请求
* 通过response.body().byteStream()获取返回的二进制字节流
*
* @param url
* @return
*/
public Reader getSyncBackCharReader(String url) {
Request request = new Request.Builder()
.url(url)
.build();
Call call = okHttpClient.newCall(request);
try {
Response response = call.execute();
// 将response转化成String
Reader responseStr = response.body().charStream();
return responseStr;
} catch (IOException e) {
Logger.e("GET同步请求解析为Reader异常" + e.toString());
e.printStackTrace();
}
return null;
}
/**
* get异步请求不传参数
* 通过response.body().string()获取返回的字符串
* 异步返回值不能更新UI,要开启新线程
*
* @param url
* @return
*/
public String getAsynBackStringWithoutParms(String url, final MyDataCallBack myDataCallBack) {
final Request request = new Request.Builder()
.url(url)
.build();
Call call = okHttpClient.newCall(request);
try {
myDataCallBack.onBefore(request);
// 请求加入调度
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// Logger.e("GET异步请求为String失败"+e.toString());
myDataCallBack.requestFailure(request, e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
responseStrGETAsyn = response.body().string();
try {
myDataCallBack.requestSuccess(responseStrGETAsyn);
} catch (Exception e) {
e.printStackTrace();
Logger.e("GET异步请求为String解析异常失败" + e.toString());
}
}
});
myDataCallBack.onAfter();
} catch (Exception e) {
Logger.e("GET异步请求解析为String异常" + e.toString());
e.printStackTrace();
}
return responseStrGETAsyn;
}
/**
* get异步请求传参数(可以传null)
* 通过response.body().string()获取返回的字符串
* 异步返回值不能更新UI,要开启新线程
*
* @param url
* @return
*/
public String getAsynBackStringWithParms(String url, Map<String, String> params, final MyDataCallBack myDataCallBack) {
if (params == null) {
params = new HashMap<>();
}
// 请求url(baseUrl+参数)
String doUrl = urlJoint(url, params);
final Request request = new Request.Builder()
.url(doUrl)
// .header("Cookie", "自动管理更新需要携带的Cookie")
.build();
Call call = okHttpClient.newCall(request);
try {
myDataCallBack.onBefore(request);
// 请求加入调度
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// Logger.e("GET异步请求为String失败"+e.toString());
myDataCallBack.requestFailure(request, e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
responseStrGETAsyn = response.body().string();
try {
myDataCallBack.requestSuccess(responseStrGETAsyn);
} catch (Exception e) {
e.printStackTrace();
Logger.e("GET异步请求为String解析异常失败" + e.toString());
}
}
});
myDataCallBack.onAfter();
} catch (Exception e) {
Logger.e("GET异步请求解析为String异常" + e.toString());
e.printStackTrace();
}
return responseStrGETAsyn;
}
/**
* post异步请求map传参
* 通过response.body().string()获取返回的字符串
* 异步返回值不能更新UI,要开启新线程
*
* @param url
* @return
*/
public String postAsynBackString(String url, Map<String, String> params, final MyDataCallBack myDataCallBack) {
RequestBody requestBody;
if (params == null) {
params = new HashMap<>();
}
FormBody.Builder builder = new FormBody.Builder();
/**
* 在这对添加的参数进行遍历
*/
addMapParmsToFromBody(params, builder);
requestBody = builder.build();
String realURL = urlJoint(url, null);
//结果返回
final Request request = new Request.Builder()
.url(realURL)
.post(requestBody)
.build();
Call call = okHttpClient.newCall(request);
try {
myDataCallBack.onBefore(request);
// 请求加入调度
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
myDataCallBack.requestFailure(request, e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
responseStrGETAsyn = response.body().string();//此处也可以解析为byte[],Reader,InputStream
try {
myDataCallBack.requestSuccess(responseStrGETAsyn);
} catch (Exception e) {
e.printStackTrace();
Logger.e("POST异步请求为String解析异常失败" + e.toString());
}
}
});
myDataCallBack.onAfter();
} catch (Exception e) {
Logger.e("POST异步请求解析为String异常" + e.toString());
e.printStackTrace();
}
return responseStrGETAsyn;
}
private void addMapParmsToFromBody(Map<String, String> params, FormBody.Builder builder) {
for (Map.Entry<String, String> map : params.entrySet()) {
String key = map.getKey();
String value;
/**
* 判断值是否是空的
*/
if (map.getValue() == null) {
value = "";
} else {
value = map.getValue();
}
/**
* 把key和value添加到formbody中
*/
builder.add(key, value);
}
}
/**
* post异步请求json传参
* 通过response.body().string()获取返回的字符串
* 异步返回值不能更新UI,要开启新线程
*
* @param url
* @return
*/
public String postAsynRequireJson(String url, Map<String, String> params, final MyDataCallBack myDataCallBack) {
if (params == null) {
params = new HashMap<>();
}
// 将map转换成json,需要引入Gson包
String mapToJson = new Gson().toJson(params);
final String realURL = urlJoint(url, null);
final Request request = buildJsonPostRequest(realURL, mapToJson);
Call call = okHttpClient.newCall(request);
try {
myDataCallBack.onBefore(request);
// 请求加入调度
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
myDataCallBack.requestFailure(request, e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
responseStrGETAsyn = response.body().string();//此处也可以解析为byte[],Reader,InputStream
try {
myDataCallBack.requestSuccess(responseStrGETAsyn);
} catch (Exception e) {
e.printStackTrace();
Logger.e("POST异步请求为String解析异常失败" + e.toString());
}
}
});
myDataCallBack.onAfter();
} catch (Exception e) {
Logger.e("POST异步请求解析为String异常" + e.toString());
e.printStackTrace();
}
return responseStrGETAsyn;
}
/**
* Json_POST请求参数
*
* @param url url
* @param json json
* @return requestBody
*/
private Request buildJsonPostRequest(String url, String json) {
// RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
RequestBody requestBody = RequestBody.create(JSON, json);
return new Request.Builder().url(url).post(requestBody).build();
}
/**
* String_POST请求参数
*
* @param url url
* @param json json
* @return requestBody
*/
private Request buildStringPostRequest(String url, String json) {
RequestBody requestBody = RequestBody.create(MEDIA_TYPE_MARKDOWN, json);
return new Request.Builder().url(url).post(requestBody).build();
}
/**
* @param url 实际URL的path
* @param params
* @return
*/
private static String urlJoint(String url, Map<String, String> params) {
StringBuilder realURL = new StringBuilder(Constant.URL);
realURL = realURL.append(url);
boolean isFirst = true;
if (params == null) {
params = new HashMap<>();
} else {
Set<Map.Entry<String, String>> entrySet = params.entrySet();
for (Map.Entry<String, String> entry : entrySet) {
if (isFirst && !url.contains("?")) {
isFirst = false;
realURL.append("?");
} else {
realURL.append("&");
}
realURL.append(entry.getKey());
realURL.append("=");
if (entry.getValue() == null) {
realURL.append(" ");
} else {
realURL.append(entry.getValue());
}
}
}
return realURL.toString();
}
/**
* 基于http的文件上传(传入文件名和key)
* 通过addFormDataPart
*
* @param url URL的Path部分
* @param myDataCallBack 自定义回调接口
* 将file作为请求体传入到服务端.
* @param fileKey 文件传入服务器的键"image"
* @fileName: "pic.png"
*/
private void upLoadMultiFileSimple(String url, String fileName, String fileKey, final MyDataCallBack myDataCallBack) {
File file = new File(Environment.getExternalStorageDirectory(), fileName);
RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(fileKey, fileName, fileBody)
.build();
final String realURL = urlJoint(url, null);
final Request request = new Request.Builder()
.url(realURL)
.post(requestBody)
.build();
Call call = okHttpClient.newCall(request);
try {
myDataCallBack.onBefore(request);
// 请求加入调度
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
myDataCallBack.requestFailure(request, e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
try {
myDataCallBack.requestSuccess(responseStrGETAsyn);
} catch (Exception e) {
e.printStackTrace();
Logger.e("POST异步文件上传失败" + e.toString());
}
}
});
myDataCallBack.onAfter();
} catch (Exception e) {
Logger.e("POST异步文件上传异常" + e.toString());
e.printStackTrace();
}
}
/**
* 基于http的文件上传(传入文件数组和key)混合参数和文件请求
* 通过addFormDataPart可以添加多个上传的文件
*
* @param url URL的Path部分
* @param myDataCallBack 自定义回调接口
* 将file作为请求体传入到服务端.
* @param files 上传的文件
* @param fileKeys 上传的文件key集合
*/
private void upLoadMultiFile(String url, File[] files, String[] fileKeys, Map<String, String> params, final MyDataCallBack myDataCallBack) {
if (params == null) {
params = new HashMap<>();
}
final String realURL = urlJoint(url, null);
FormBody.Builder builder = new FormBody.Builder();
addMapParmsToFromBody(params, builder);
RequestBody requestBody = builder.build();
MultipartBody.Builder multipartBody = new MultipartBody.Builder();
multipartBody.setType(MultipartBody.ALTERNATIVE)
.addPart(requestBody);
if (files != null) {
RequestBody fileBody = null;
for (int i = 0; i < files.length; i++) {
File file = files[i];
String fileName = file.getName();
fileBody = RequestBody.create(MediaType.parse(guessMimeType(fileName)), file);
//TODO 根据文件名设置contentType
multipartBody.addPart(Headers.of("Content-Disposition",
"form-data; name=\"" + fileKeys[i] + "\"; filename=\"" + fileName + "\""),
fileBody);
}
}
final Request request = new Request.Builder()
.url(realURL)
.post(multipartBody.build())
.build();
Call call = okHttpClient.newCall(request);
try {
myDataCallBack.onBefore(request);
// 请求加入调度
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
myDataCallBack.requestFailure(call.request(), e);
}
@Override
public void onResponse(Call call, Response response) {
try {
myDataCallBack.requestSuccess(response.body().string());
} catch (Exception e) {
e.printStackTrace();
Logger.e("POST异步文件上传失败" + e.toString());
}
}
});
myDataCallBack.onAfter();
} catch (Exception e) {
Logger.e("POST异步文件上传异常" + e.toString());
e.printStackTrace();
}
}
private String guessMimeType(String fileName) {
FileNameMap fileNameMap = URLConnection.getFileNameMap();
String contentTypeFor = fileNameMap.getContentTypeFor(fileName);
if (contentTypeFor == null) {
contentTypeFor = "application/octet-stream";
}
return contentTypeFor;
}
/**
* 文件下载
* @param url path路径
* @param destFileDir 本地存储的文件夹路径
* @param myDataCallBack 自定义回调接口
*/
private void downLoadFileAsyn(final String url, final String destFileDir, final MyDataCallBack myDataCallBack){
String realURL=urlJoint(url,null);
Request request=new Request.Builder()
.url(realURL)
.build();
Call call=okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
myDataCallBack.requestFailure(call.request(),e);
}
@Override
public void onResponse(Call call, Response response) {
InputStream is = null;
byte[] buf = new byte[2048];
int len = 0;
FileOutputStream fos = null;
is = response.body().byteStream();
File file = new File(destFileDir, getFileName(url));
try {
fos = new FileOutputStream(file);
while ((len = is.read(buf)) != -1)
{
fos.write(buf, 0, len);
}
fos.flush();
} catch (IOException e) {
Logger.e("文件下载异常:",e.getMessage());
e.printStackTrace();
}finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
Logger.e("文件流关闭异常:",e.getMessage());
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
Logger.e("文件流关闭异常:",e.getMessage());
e.printStackTrace();
}
}
}
//如果下载文件成功,第一个参数为文件的绝对路径
sendSuccessResultCallback(file.getAbsolutePath(), myDataCallBack);
myDataCallBack.requestSuccess(response.body().toString());
}
});
}
private String getFileName(String url) {
int separatorIndex = url.lastIndexOf("/");
return (separatorIndex < 0) ? url : url.substring(separatorIndex + 1, url.length());
}
private void sendSuccessResultCallback(final String absolutePath, final MyDataCallBack myDataCallBack) {
ThreadPoolUtil.execute(new Runnable() {
@Override
public void run() {
if (myDataCallBack!=null){
myDataCallBack.requestSuccess(absolutePath);
}
}
});
}
}