https://github.com/square/okhttp
package com.yaoxin.doctor.httpservice;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;
import com.yaoxin.doctor.bean.PublicIp;
import com.yaoxin.doctor.interFace.ReqCallBack;
import com.yaoxin.doctor.utils.SharePreferenceUtil;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import static java.lang.String.valueOf;
/**
* 基于okhttp-3.10.0.jar进行二次封装的网络请求类
*
* OkHttpClient:客户端对象
*
* @author Eleven
*/
@SuppressLint("DefaultLocale")
public class MyOkHttp extends OkHttpClient {
private static final String URL_PREFIX_HTTP = "http";
private static final String RESULT_SUCCESS = "0";
private static final String PLATFORM = "platform";
private static final String TOKEN = "token";
private static final String DID = "did";
private static final String PARAM_VERSION = "version";
private static final String MSG_NETWORK_ERROR = "网络错误";
private static final String MSG_CDCARD_ERROR = "文件下载出错";
private static volatile MyOkHttp mInstance;// 单利引用
private OkHttpClient mOkHttpClient;// okHttpClient 实例
private Handler okHttpHandler;// 全局处理子线程和M主线程通信
private static final String TAG = "MyOkHttp";
/**
* 初始化MyOkHttp
*/
public MyOkHttp(Context context) {
// TODO Auto-generated constructor stub
// 初始化OkHttpClient
mOkHttpClient = new OkHttpClient().newBuilder()
.connectTimeout(10, TimeUnit.SECONDS)// 设置超时时间
.readTimeout(10, TimeUnit.SECONDS)// 设置读取超时时间
.writeTimeout(10, TimeUnit.SECONDS)// 设置写入超时时间
.addInterceptor(new LogInterceptor())
.build();
// 初始化Handler
okHttpHandler = new Handler(context.getMainLooper());
}
/**
* 获取单例引用
*
* @return
*/
public static MyOkHttp getInstance(Context context) {
if (mInstance == null) {
synchronized (MyOkHttp.class) {
mInstance = new MyOkHttp(context);
}
}
return mInstance;
}
// MyOkHttp.requestGetBySyn
// 请求药信API GET接口,并将正确的返回值缓存到本地文件
// 参数:
// url - 接口地址
// target - 缓存文件名(自动添加缓存路径)
// callback - 回调
// 说明:
// - 自动实例化,调用者只需使用Utils.requestGetBySyn(...)即可调用
// - target中自动添加.json后缀(防止疏忽)
// - 自动添加uid与version参数到url,调用者url中无需包含
// - 已自动对返回值进行了错误判断,返回值不是JSON,或接口中返回“错误”,均自动进入onFailure处理,
// 调用者无需在onSuccess中对返回值再次进行解析判断,直接拿取数据处理即可
// - 若接口返回错误(包括即便是正确的JSON,但接口中返回“错误”的情况),均不会进行本地缓存,
// 即某一次的错误数据不会覆盖原有正确的缓存数据
// - onSuccess处理中,可直接使用获取结果字符串,无需再通过读取缓存文件获取结果
// - onFailure处理中,可直接使用msg参数获取错误字符串进行后续处理
public static Call requestGetBySyn(Context context, String url,
String target, ReqCallBack callBack) {
return MyOkHttp.getInstance(context).requestGetByAsyn(context, url,
target, callBack);
}
// MyOkHttp.requestPostBySyn
// 请求药信API POST接口,
// 参数:
// url - 接口地址(自动添加5iyaoxin前缀)
// map - 上传数据
// callback - 回调
// 说明:
// - 自动实例化,调用者只需使用MyOkHttp.requestPostBySyn(...)即可调用
// - 已自动对返回值进行了错误判断,返回值不是JSON,或接口中返回“错误”,均自动进入onFailure处理,
// 调用者无需在onSuccess中对返回值再次进行解析判断,直接拿取数据处理即可
// 某一次的错误数据不会覆盖原有正确的缓存数据
// - onSuccess处理中,可直接使用获取结果字符串,无需再通过读取缓存文件获取结果
// - onFailure处理中,可直接使用msg参数获取错误字符串进行后续处理
public static Call requestPostBySyn(Context context, String url,
Map map, ReqCallBack callBack) {
return MyOkHttp.getInstance(context).requestPostByAsyn(context, url,
map, callBack);
}
// MyOkHttp.requestPostFileBySyn
// 请求药信API POST接口上传文件
// 参数:
// url - 接口地址(自动添加5iyaoxin前缀)
// map - 上传文件
// map - 上传数据
// callback - 回调
// 说明:
// - 自动实例化,调用者只需使用MyOkHttp.requestPostFileBySyn(...)即可调用
// - 已自动对返回值进行了错误判断,返回值不是JSON,或接口中返回“错误”,均自动进入onFailure处理,
// 调用者无需在onSuccess中对返回值再次进行解析判断,直接拿取数据处理即可
// 某一次的错误数据不会覆盖原有正确的缓存数据
// - onSuccess处理中,可直接使用获取结果字符串,无需再通过读取缓存文件获取结果
// - onFailure处理中,可直接使用msg参数获取错误字符串进行后续处理
public static Call requestPostFileBySyn(Context context, String url,
File file, Map map, ReqCallBack callBack) {
return MyOkHttp.getInstance(context).requestPostByFileAsyn(context,
url, file, map, callBack);
}
// MyOkHttp.doDownloading
// 下载指定url的文件到缓存路径(自动添加http前缀)
// 参数:
// url - 文件地址
// target - 缓存文件名(自动添加缓存路径)
// callback - 回调
// 说明:
// - 自动实例化,调用者只需使用MyOkHttp.doDownloading(...)即可调用
// - url中无需包含http://部分
public static Call doDownloading(Context context, String url,
String target, ReqCallBack callBack) {
return MyOkHttp.getInstance(context).downLoad(context, url, target,
callBack);
}
/**
* okHttp get异步请求
*
* @param url 接口地址
* @param target 缓存名字
* @param callBack 请求返回数据回调
* @param 数据泛型
* @return
*/
@SuppressWarnings("unchecked")
private Call requestGetByAsyn(final Context context, String url,
String target, final ReqCallBack callBack) {
try {
if (!url.startsWith(PublicIp.URL)
&& !url.startsWith(URL_PREFIX_HTTP)) {
url = PublicIp.URL + url;
}
// 去判断是否有用户号和版本号
url = getUrlWithExtras(context, url);
if (!TextUtils.isEmpty(target)) {
// 检查缓存名称是否合格
if (!target.toLowerCase().endsWith(".json")) {
target = target + ".json";
}
// 检查缓存名称是否包含路径
if (!target.startsWith(context.getFilesDir().getAbsolutePath())) {
target = getCacheFileName(target, context);
}
}
url = url.replace(" ","");
final String targetFileName = target;
final Request request = new Request.Builder().get().url(url)
.build();
final Call call = mOkHttpClient.newCall(request);
if (PublicIp.URL.contains("test")) {
Log.i(TAG, "requestGetByAsyn: " + url);
}
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.i(TAG, "onFailure: " + e.toString());
boolean isDestoryed = false;
try {
Activity activity = (Activity) context;
if (activity.isFinishing()) {
isDestoryed = true;
}
} catch (Exception e1) {
// TODO: handle exception
}
if (isDestoryed) {
return;
}
if (!call.isCanceled()) {
failedCallBack(MSG_NETWORK_ERROR, callBack);
}
}
@Override
public void onResponse(Call call, Response response)
throws IOException {
boolean isDestoryed = false;
try {
Activity activity = (Activity) context;
if (activity.isFinishing()) {
isDestoryed = true;
}
} catch (Exception e) {
// TODO: handle exception
}
if (isDestoryed) {
return;
}
if (response.isSuccessful()) {
// 接口成功拿到数据
String result = response.body().string();
Log.i(TAG, "onResponse: " + result);
/**
* logout代码
*/
// 辨别接口返回标识码
String error = getErrorOfReponseString(result);
if (TextUtils.equals(error, "信息错误!")) {
}
if (error.equals(RESULT_SUCCESS) && callBack != null) {
// 自动缓存数据以.json的文件存储
saveContentToFile(result, targetFileName);
// 成功回调
successCallBack((T) result, callBack);
} else {
String errorMsg = "";
try {
JSONObject obj = new JSONObject(result);
if (obj.has("msg")) {
errorMsg = obj.getString("msg");
}
} catch (JSONException e) {
e.printStackTrace();
}
failedCallBack(errorMsg, callBack);
}
} else {
String result = response.body().string();
Log.i(TAG, "onResponse: " + result);
failedCallBack(MSG_NETWORK_ERROR, callBack);
}
}
});
return call;
} catch (Exception e) {
return null;
}
}
/**
* okHttp post异步请求
*
* @param url 接口地址
* @param map 上传数据
* @param callBack 请求返回数据回调
* @param 数据泛型
* @return
*/
@SuppressWarnings({"unchecked"})
private Call requestPostByAsyn(Context context, String url,
Map map, final ReqCallBack callBack) {
try {
if (!url.startsWith(PublicIp.URL)
&& !url.startsWith(URL_PREFIX_HTTP)) {
url = PublicIp.URL + url;
}
// 去判断是否有用户号和版本号
url = getUrlWithExtras(context, url);
// MultipartBody.Builder requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM);
FormBody.Builder requestBody = new FormBody.Builder();
if (map != null) {
// map 里面是请求中所需要的 key 和 value
for (Map.Entry entry : map.entrySet()) {
requestBody.add(valueOf(entry.getKey()), valueOf(entry.getValue()));
}
// requestBody.add(PARAM_VERSION, getVersion(context));
// requestBody.add(PLATFORM, "Android");
// requestBody.add(TOKEN, "token");
// requestBody.add(DID, getUserId(context));
}
final Request request = new Request.Builder().post(requestBody.build())
.url(url).build();
final Call call = mOkHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
failedCallBack(MSG_NETWORK_ERROR, callBack);
}
@Override
public void onResponse(Call call, Response response)
throws IOException {
Log.e(TAG, "onResponse: "+response.message().toString() );
if (response.isSuccessful()) {
// 接口成功拿到数据
String result = response.body().string();
// 辨别接口返回标识码
String error = getErrorOfReponseString(result);
if (error.equals(RESULT_SUCCESS) && callBack != null) {
// 成功回调
successCallBack((T) result, callBack);
} else {
failedCallBack(error, callBack);
}
} else {
failedCallBack(MSG_NETWORK_ERROR, callBack);
}
}
});
return call;
} catch (Exception e) {
return null;
}
}
/**
* okHttp post异步请求
*
* @param url 接口地址
* @param map 上传数据
* @param file 上传文件
* @param callBack 请求返回数据回调
* @param 数据泛型
* @return
*/
@SuppressWarnings({"unchecked"})
private Call requestPostByFileAsyn(final Context context, String url,
File file, Map map, final ReqCallBack callBack) {
try {
if (!url.startsWith(PublicIp.URL)
&& !url.startsWith(URL_PREFIX_HTTP)) {
url = PublicIp.URL + url;
}
MultipartBody.Builder requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM);
if (file != null) {
// MediaType.parse() 里面是上传的文件类型。
RequestBody body = RequestBody.create(
MediaType.parse("image/*"), file);
String filename = file.getName();
// 参数分别为, 请求key ,文件名称 , RequestBody
requestBody.addFormDataPart("files", filename, body);
requestBody.addFormDataPart("type", "1");
requestBody.addFormDataPart(TOKEN, SignUtils.getToken(context));
requestBody.addFormDataPart(PARAM_VERSION, getVersion(context));
requestBody.addFormDataPart(PLATFORM, "Android");
requestBody.addFormDataPart(DID, getUserId(context));
}
if (map != null) {
// map 里面是请求中所需要的 key 和 value
for (Map.Entry entry : map.entrySet()) {
requestBody.addFormDataPart(valueOf(entry.getKey()), valueOf(entry.getValue()));
}
}
final Request request = new Request.Builder()
.post(requestBody.build()).url(url).build();
final Call call = mOkHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e("TAG", "==" + e.toString());
boolean isDestoryed = false;
try {
Activity activity = (Activity) context;
if (activity.isFinishing()) {
isDestoryed = true;
}
} catch (Exception e1) {
// TODO: handle exception
}
if (isDestoryed) {
return;
}
failedCallBack(MSG_NETWORK_ERROR, callBack);
}
@Override
public void onResponse(Call call, Response response)
throws IOException {
Log.e("TAG", "==" + response.body().string());
boolean isDestoryed = false;
try {
Activity activity = (Activity) context;
if (activity.isFinishing()) {
isDestoryed = true;
}
} catch (Exception e) {
// TODO: handle exception
}
if (isDestoryed) {
return;
}
if (response.isSuccessful()) {
// 接口成功拿到数据
String result = response.body().string();
// 辨别接口返回标识码
/**
* logout代码
*/
// 辨别接口返回标识码
String error = getErrorOfReponseString(result);
if (TextUtils.equals(error, "信息错误!")) {
}
if (error.equals(RESULT_SUCCESS) && callBack != null) {
// 成功回调
successCallBack((T) result, callBack);
} else {
failedCallBack(error, callBack);
}
} else {
failedCallBack(MSG_NETWORK_ERROR, callBack);
}
}
});
return call;
} catch (Exception e) {
return null;
}
}
/**
* okHttp get异步请求
*
* @param url 文件地址
* @param target 下载路径
* @param callBack 请求返回数据回调
* @param 数据泛型
* @return
*/
@SuppressWarnings("unchecked")
private Call downLoad(Context context, String url, String target,
final ReqCallBack callBack) {
try {
// 是否添加了文件路径
if (!target.startsWith(context.getFilesDir().getAbsolutePath())) {
target = getCacheFileName(target, context);
}
final String targetFileName = target;
final Request request = new Request.Builder().get().url(url)
.build();
final Call call = mOkHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
failedCallBack(MSG_NETWORK_ERROR, callBack);
}
@Override
public void onResponse(Call call, Response response)
throws IOException {
if (response.isSuccessful()) {
try {
// 接口成功拿到数据
// 将响应数据转化为输入流数据
InputStream inputStream = response.body()
.byteStream();
FileOutputStream out = null;// 文件输出流
if (targetFileName.endsWith(".jpg")) {
// 将输入流数据转化为Bitmap位图数据
Bitmap bitmap = BitmapFactory
.decodeStream(inputStream);
File file = new File(targetFileName);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();// 创建文件夹
}
file.createNewFile();
// 创建文件输出流对象用来向文件中写入数据
out = new FileOutputStream(file);
// 将bitmap存储为jpg格式的图片
if (bitmap != null) {
bitmap.compress(Bitmap.CompressFormat.JPEG,
100, out);
}
} else {
File file = new File(targetFileName);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();// 创建文件夹
}
file.createNewFile();
// 创建文件输出流对象用来向文件中写入数据
out = new FileOutputStream(file);
byte[] buf = new byte[1024 * 8];
int ch;
while ((ch = inputStream.read(buf)) != -1) {
out.write(buf, 0, ch);// 将获取到的流写入文件中
}
}
// 刷新文件流
if (out != null) {
out.flush();
out.close();
}
successCallBack((T) targetFileName, callBack);
} catch (Exception e) {
// TODO: handle exception
failedCallBack(MSG_CDCARD_ERROR, callBack);
}
} else {
failedCallBack(MSG_NETWORK_ERROR, callBack);
}
}
});
return call;
} catch (Exception e) {
return null;
}
}
/**
* 统一同意处理成功信息
*
* @param result
* @param callBack
* @param
*/
private void successCallBack(final T result,
final ReqCallBack callBack) {
okHttpHandler.post(new Runnable() {
@Override
public void run() {
if (callBack != null) {
callBack.onReqSuccess(result);
}
}
});
}
/**
* 统一处理失败信息
*
* @param errorMsg
* @param callBack
* @param
*/
private void failedCallBack(final String errorMsg,
final ReqCallBack callBack) {
okHttpHandler.post(new Runnable() {
@Override
public void run() {
if (callBack != null) {
callBack.onReqFailed(errorMsg);
}
}
});
}
// 自动为在GET url中添加member_phone与version参数
public static String getUrlWithExtras(Context context, String url) {
if (url.indexOf(DID) == -1) {
url = getUrlWithParam(DID, getUserId(context), url);
// url = getUrlWithParam(DID, getUserId(context), url);
}
if (url.indexOf(PARAM_VERSION) == -1) {
url = getUrlWithParam(PARAM_VERSION, getVersion(context), url);
}
if (url.indexOf(PLATFORM) == -1) {
url = getUrlWithParam(PLATFORM, "Android", url);
}
if (url.indexOf(TOKEN) == -1) {
url = getUrlWithParam(TOKEN, SignUtils.getToken(context), url);
}
// String unixtime = System.currentTimeMillis() / 1000 + "";
// String sign = UtilsTool.getSign(unixtime).trim();
//
// url = getUrlWithParam(UtilsTool.PARAM_UNIXTIME, unixtime, url);
// url = getUrlWithParam(UtilsTool.PARAM_SIGN, sign, url);
return url;
}
// 直接获取用户id(手机号)
public static String getUserId(Context mContext) {
try {
SharedPreferences userinfo = mContext.getSharedPreferences(
SharePreferenceUtil.SHARE_NAME, Context.MODE_PRIVATE);
return userinfo.getString("userid", "");
} catch (Exception e) {
return "";
}
}
// 获取版本号
public static String getVersion(Context context) {
try {
PackageInfo pi = context.getPackageManager().getPackageInfo(
context.getPackageName(), 0);
// 去除版本号中的逗号
String versionName = pi.versionName.replace(".", "");
return versionName;
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return "";
}
}
private static String getUrlWithParam(String paramName, String paramValue,
String url) {
if (url.contains(paramName + "=")) {
return url;
} else {
if (url.contains("?")) {
return String.format("%1$s&%2$s=%3$s", url, paramName,
paramValue);
} else {
return String.format("%1$s?%2$s=%3$s", url, paramName,
paramValue);
}
}
}
// 获取缓存文件名
public static String getCacheFileName(String filename, Context mContext) {
String cacheDir = mContext.getFilesDir().getAbsolutePath();
if (filename.startsWith("/")) {
return cacheDir + filename;
} else {
return cacheDir + "/" + filename;
}
}
// 将String内容保存到文件中
// 返回值: true - 成功 false - 失败
public static Boolean saveContentToFile(String content, String filename) {
try {
File f = new File(filename);
if (!f.exists()) {
f.getParentFile().mkdirs();
f.createNewFile();
}
FileOutputStream ofile = new FileOutputStream(f);
ofile.write(content.getBytes());
ofile.close();
return true;
} catch (Exception e) {
return false;
}
}
// 返回值:
// 是JSON且result=="1" 正确 result!="1" 错误:resultString
// 是JSON且state=="1" 正确 state!="1" 错误:stateString
// 是JSON且没有result或state 正确
// 不是JSON且返回值为"1" 正确 返回值!="1" 错误:网络错误
private static String getErrorOfReponseString(String response) {
if (isJSON(response)) {
try {
JSONObject json = new JSONObject(response);
if (json.has("result")) {
return json.getString("result");
} else if (json.has("state")) {
return json.getString("state");
} else if (json.has("status")) {
return json.getString("status");
} else {
return RESULT_SUCCESS;
}
} catch (JSONException e) {
return RESULT_SUCCESS;// JSONArray
}
} else if (response.equals(RESULT_SUCCESS)) {
return RESULT_SUCCESS;
} else {
return "网络错误";
}
}
// 判定字符串是否是JSONObject或JSONArray
public static boolean isJSON(String content) {
try {
new JSONObject(content);
} catch (JSONException e) {
try {
new JSONArray(content);
} catch (JSONException c) {
return false;
}
}
return true;
}
}
reqcall
package com.yaoxin.doctor.interFace;
/**
* okhttp二次封装类回调方法
*
* @author Eleven
*
* @param
*/
public interface ReqCallBack {
/**
* 响应成功
*/
void onReqSuccess(T result);
/**
* 响应失败
*/
void onReqFailed(String errorMsg);
}