public class OkHttp3Utils {
private volatile static OkHttp3Utils mInstance;
private OkHttpClient mOkHttpClient;
private Handler mHandler;
private Context mContext;
private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
private OkHttp3Utils(Context context) {
super();
Builder clientBuilder = new OkHttpClient().newBuilder();
clientBuilder.readTimeout(30, TimeUnit.SECONDS);
clientBuilder.connectTimeout(15, TimeUnit.SECONDS);
clientBuilder.writeTimeout(60, TimeUnit.SECONDS);
mOkHttpClient = clientBuilder.build();
this.mContext = context.getApplicationContext();
mHandler = new Handler(mContext.getMainLooper());
}
public static OkHttp3Utils getInstance(Context context) {
OkHttp3Utils temp = mInstance;
if (temp == null) {
synchronized (OkHttp3Utils.class) {
temp = mInstance;
if (temp == null) {
temp = new OkHttp3Utils(context);
mInstance = temp;
}
}
}
return temp;
}
/**
* 设置请求头
*
* @param headersParams
* @return
*/
private Headers SetHeaders(Map<String, String> headersParams) {
Headers headers = null;
Headers.Builder headersbuilder = new Headers.Builder();
if (headersParams != null) {
Iterator<String> iterator = headersParams.keySet().iterator();
String key = "";
while (iterator.hasNext()) {
key = iterator.next().toString();
headersbuilder.add(key, headersParams.get(key));
}
}
headers = headersbuilder.build();
return headers;
}
/**
* post请求参数
*
* @param BodyParams
* @return
*/
private RequestBody SetPostRequestBody(Map<String, String> BodyParams) {
RequestBody body = null;
FormBody.Builder formEncodingBuilder = new FormBody.Builder();
if (BodyParams != null) {
Iterator<String> iterator = BodyParams.keySet().iterator();
String key = "";
while (iterator.hasNext()) {
key = iterator.next().toString();
formEncodingBuilder.add(key, BodyParams.get(key));
}
}
body = formEncodingBuilder.build();
return body;
}
/**
* Post上传图片的参数
*
* @param BodyParams
* @param fileParams
* @return
*/
private RequestBody SetFileRequestBody(Map<String, String> BodyParams, Map<String, String> filePathParams) {
// 带文件的Post参数
RequestBody body = null;
MultipartBody.Builder MultipartBodyBuilder = new MultipartBody.Builder();
MultipartBodyBuilder.setType(MultipartBody.FORM);
RequestBody fileBody = null;
if (BodyParams != null) {
Iterator<String> iterator = BodyParams.keySet().iterator();
String key = "";
while (iterator.hasNext()) {
key = iterator.next().toString();
MultipartBodyBuilder.addFormDataPart(key, BodyParams.get(key));
}
}
if (filePathParams != null) {
Iterator<String> iterator = filePathParams.keySet().iterator();
String key = "";
int i = 0;
while (iterator.hasNext()) {
key = iterator.next().toString();
i++;
MultipartBodyBuilder.addFormDataPart(key, filePathParams.get(key));
fileBody = RequestBody.create(MEDIA_TYPE_PNG, new File(filePathParams.get(key)));
MultipartBodyBuilder.addFormDataPart(key, i + ".png", fileBody);
}
}
body = MultipartBodyBuilder.build();
return body;
}
/**
* get方法连接拼加参数
*
* @param mapParams
* @return
*/
private String setGetUrlParams(Map<String, String> mapParams) {
String strParams = "";
if (mapParams != null) {
Iterator<String> iterator = mapParams.keySet().iterator();
String key = "";
while (iterator.hasNext()) {
key = iterator.next().toString();
strParams += "&" + key + "=" + mapParams.get(key);
}
}
return strParams;
}
/**
* 实现post请求
*
* @param reqUrl
* @param headersParams
* @param params
* @param callback
*/
public void doPost(String reqUrl, Map<String, String> headersParams, Map<String, String> params, final NetCallback callback) {
Request.Builder RequestBuilder = new Request.Builder();
RequestBuilder.url(reqUrl);// 添加URL地址
RequestBuilder.method("POST", SetPostRequestBody(params));
RequestBuilder.headers(SetHeaders(headersParams));// 添加请求头
Request request = RequestBuilder.build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onResponse(final Call call, final Response response) throws IOException {
mHandler.post(new Runnable() {
@Override
public void run() {
callback.onSuccess(0, response.body().toString());
call.cancel();
}
});
}
@Override
public void onFailure(final Call call, final IOException exception) {
mHandler.post(new Runnable() {
@Override
public void run() {
callback.onFailure(-1, exception.getMessage());
call.cancel();
}
});
}
});
}
/**
* 实现get请求
*
* @param reqUrl
* @param headersParams
* @param params
* @param callback
*/
public void doGet(String reqUrl, Map<String, String> headersParams, Map<String, String> params, final NetCallback callback) {
Request.Builder RequestBuilder = new Request.Builder();
RequestBuilder.url(reqUrl + setGetUrlParams(params));// 添加URL地址 自行加 ?
RequestBuilder.headers(SetHeaders(headersParams));// 添加请求头
Request request = RequestBuilder.build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onResponse(final Call call, final Response response) throws IOException {
mHandler.post(new Runnable() {
@Override
public void run() {
callback.onSuccess(0, response.body().toString());
call.cancel();
}
});
}
@Override
public void onFailure(final Call call, final IOException exception) {
mHandler.post(new Runnable() {
@Override
public void run() {
callback.onFailure(-1, exception.getMessage());
call.cancel();
}
});
}
});
}
/**
* 实现加载图片
*
* @param context
* @param reqUrl
* @param headersParams
* @param imageView
* @param defResImag imageView.setImageResource(context.getResources().getIdentifier(defResImag, "drawable", context.getPackageName()));
*/
public void loadImage(final Context context, final String reqUrl, Map<String, String> headersParams, final ImageView imageView, final String defResImag) {
Bitmap result;
// 从内存缓存中获取图片
final ImageMemoryCache memoryCache = new ImageMemoryCache(context);
result = memoryCache.getBitmapFromCache(reqUrl);
if (result != null) {
imageView.setImageBitmap(result);
return;
}
// 从硬盘缓存中获取图片
final ImageFileCache fileCache = new ImageFileCache(context);
result = fileCache.getImage(context, reqUrl);
if (result != null) {
imageView.setImageBitmap(result);
// 添加到内存缓存
memoryCache.addBitmapToCache(reqUrl, result);
return;
}
Request.Builder RequestBuilder = new Request.Builder();
RequestBuilder.url(reqUrl);// 添加URL地址
// RequestBuilder.headers(SetHeaders(headersParams));// 添加请求头
Request request = RequestBuilder.build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onResponse(final Call call, final Response response) throws IOException {
byte[] bytes = response.body().bytes();
final Bitmap decodeStream = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
mHandler.post(new Runnable() {
@Override
public void run() {
try {
if (decodeStream != null) {
imageView.setImageBitmap(decodeStream);
// 缓存在文件
fileCache.saveBitmap(context, decodeStream, reqUrl);
// 缓存在内存
memoryCache.addBitmapToCache(reqUrl, decodeStream);
} else {
// 加载图片
imageView.setImageResource(context.getResources().getIdentifier(defResImag, "drawable", context.getPackageName()));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
call.cancel();
}
}
});
}
@Override
public void onFailure(final Call call, final IOException exception) {
mHandler.post(new Runnable() {
@Override
public void run() {
// 加载图片
imageView.setImageResource(context.getResources().getIdentifier(defResImag, "drawable", context.getPackageName()));
call.cancel();
}
});
}
});
}
public abstract class NetCallback {
public abstract void onFailure(int code, String msg);
public abstract void onSuccess(int code, String content);
public abstract void loadImage(Bitmap bitmap);
}
}
public class ImageMemoryCache {
/**
* 从内存读取数据速度是最快的,为了更大限度使用内存,这里使用了两层缓存。 硬引用缓存不会轻易被回收,用来保存常用数据,不常用的转入软引用缓存。
*/
private static final int SOFT_CACHE_SIZE = 15; // 软引用缓存容量
private static LruCache<String, Bitmap> mLruCache; // 硬引用缓存
private static LinkedHashMap<String, SoftReference<Bitmap>> mSoftCache; // 软引用缓存
public ImageMemoryCache(Context context) {
int memClass = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
int cacheSize = 1024 * 1024 * memClass / 4; // 硬引用缓存容量,为系统可用内存的1/4
mLruCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
if (value != null)
return value.getRowBytes() * value.getHeight();
else
return 0;
}
@Override
protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
if (oldValue != null)
// 硬引用缓存容量满的时候,会根据LRU算法把最近没有被使用的图片转入此软引用缓存
mSoftCache.put(key, new SoftReference<Bitmap>(oldValue));
}
};
mSoftCache = new LinkedHashMap<String, SoftReference<Bitmap>>(SOFT_CACHE_SIZE, 0.75f, true) {
private static final long serialVersionUID = 6040103833179403725L;
@Override
protected boolean removeEldestEntry(Entry<String, SoftReference<Bitmap>> eldest) {
if (size() > SOFT_CACHE_SIZE) {
return true;
}
return false;
}
};
}
/**
* 从缓存中获取图片
*/
public Bitmap getBitmapFromCache(String url) {
Bitmap bitmap;
// 先从硬引用缓存中获取
synchronized (mLruCache) {
bitmap = mLruCache.get(url);
if (bitmap != null) {
// 如果找到的话,把元素移到LinkedHashMap的最前面,从而保证在LRU算法中是最后被删除
mLruCache.remove(url);
mLruCache.put(url, bitmap);
return bitmap;
}
}
// 如果硬引用缓存中找不到,到软引用缓存中找
synchronized (mSoftCache) {
SoftReference<Bitmap> bitmapReference = mSoftCache.get(url);
if (bitmapReference != null) {
bitmap = bitmapReference.get();
if (bitmap != null) {
// 将图片移回硬缓存
mLruCache.put(url, bitmap);
mSoftCache.remove(url);
return bitmap;
} else {
mSoftCache.remove(url);
}
}
}
return null;
}
/**
* 添加图片到缓存
*/
public void addBitmapToCache(String url, Bitmap bitmap) {
if (bitmap != null) {
synchronized (mLruCache) {
mLruCache.put(url, bitmap);
}
}
}
public void clearCache() {
mSoftCache.clear();
}
}
public class ImageFileCache {
private static final String CACHDIR = ".ImgCache";
private static final String WHOLESALE_CONV = ".cache";
private static final int MB = 1024 * 1024;
private static final int CACHE_SIZE = 10;
private static final int FREE_SD_SPACE_NEEDED_TO_CACHE = 10;
public ImageFileCache(Context ctx) {
// 清理文件缓存
removeCache(ctx,getDirectory(ctx));
}
/** 从缓存中获取图片 **/
public Bitmap getImage(Context ctx, final String url) {
final String path = getDirectory(ctx) + "/" + convertUrlToFileName(url);
File file = new File(path);
if (file.exists()) {
Bitmap bmp = BitmapFactory.decodeFile(path);
if (bmp == null) {
file.delete();
} else {
updateFileTime(path);
return bmp;
}
}
return null;
}
/** 将图片存入文件缓存 **/
public void saveBitmap(Context ctx, Bitmap bm, String url) {
if (bm == null) {
return;
}
// 判断sdcard上的空间
if (FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd(ctx)) {
// SD空间不足
return;
}
String filename = convertUrlToFileName(url);
String dir = getDirectory(ctx);
File dirFile = new File(dir);
if (!dirFile.exists())
dirFile.mkdirs();
File file = new File(dir + "/" + filename);
try {
file.createNewFile();
OutputStream outStream = new FileOutputStream(file);
bm.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
outStream.flush();
outStream.close();
} catch (FileNotFoundException e) {
Log.w("ImageFileCache", "FileNotFoundException");
} catch (IOException e) {
Log.w("ImageFileCache", "IOException");
}
}
/**
* 计算存储目录下的文件大小,
* 当文件总大小大于规定的CACHE_SIZE或者sdcard剩余空间小于FREE_SD_SPACE_NEEDED_TO_CACHE的规定
* 那么删除40%最近没有被使用的文件
*/
private boolean removeCache(Context ctx,String dirPath) {
File dir = new File(dirPath);
File[] files = dir.listFiles();
if (files == null) {
return true;
}
// if (!android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
// return false;
// }
int dirSize = 0;
for (int i = 0; i < files.length; i++) {
if (files[i].getName().contains(WHOLESALE_CONV)) {
dirSize += files[i].length();
}
}
if (dirSize > CACHE_SIZE * MB || FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd(ctx)) {
int removeFactor = (int) ((0.4 * files.length) + 1);
Arrays.sort(files, new FileLastModifSort());
for (int i = 0; i < removeFactor; i++) {
if (files[i].getName().contains(WHOLESALE_CONV)) {
files[i].delete();
}
}
}
if (freeSpaceOnSd(ctx) <= CACHE_SIZE) {
return false;
}
return true;
}
/** 修改文件的最后修改时间 **/
public void updateFileTime(String path) {
File file = new File(path);
long newModifiedTime = System.currentTimeMillis();
file.setLastModified(newModifiedTime);
}
/** 计算sdcard上的剩余空间 **/
private int freeSpaceOnSd(Context ctx) {
StatFs stat = new StatFs(getCachePath(ctx));
double sdFreeMB = ((double) stat.getAvailableBlocks() * (double) stat.getBlockSize()) / MB;
return (int) sdFreeMB;
}
/** 将url转成文件名 **/
private String convertUrlToFileName(String url) {
String[] strs = url.split("/");
return strs[strs.length - 1] + WHOLESALE_CONV;
}
/** 获得缓存目录 **/
private String getDirectory(Context ctx) {
String dir = getCachePath(ctx);
return dir;
}
/** 取SD卡路径 **/
private String getSDPath() {
File sdDir = null;
boolean sdCardExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED); // 判断sd卡是否存在
if (sdCardExist) {
sdDir = Environment.getExternalStorageDirectory(); // 获取根目录
}
if (sdDir != null) {
return sdDir.toString();
} else {
return null;
}
}
private String getCachePath(Context ctx) {
String sdCardPath = getSDPath();
if (sdCardPath != null) {
return sdCardPath + File.separator + "Android" + File.separator + "data" + File.separator + ctx.getPackageName() + File.separator + CACHDIR;
}
return ctx.getFilesDir().getAbsolutePath() + File.separator + CACHDIR;
}
/**
* 根据文件的最后修改时间进行排序
*/
private class FileLastModifSort implements Comparator<File> {
public int compare(File arg0, File arg1) {
if (arg0.lastModified() > arg1.lastModified()) {
return 1;
} else if (arg0.lastModified() == arg1.lastModified()) {
return 0;
} else {
return -1;
}
}
}
}