ImageUtils.java
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.util.LruCache;
import org.xutils.common.util.MD5;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 三级缓存的图片加载工具类
*/
public class ImageUtils {
public static final String CACHE_IMAGE_DIR = Environment.getExternalStorageDirectory().getAbsolutePath() + "/image_cache/";
private static final ExecutorService executor = Executors.newFixedThreadPool(10);
private static LruCache<String, Bitmap> lruCache;
static {
// 设置最大缓存空间为运行时内存的1/10
int maxCacheMemory = (int) (Runtime.getRuntime().maxMemory() / 8);
lruCache = new LruCache<String, Bitmap>(maxCacheMemory) {
@Override
protected int sizeOf(String key, Bitmap value) {
// 计算一个元素的缓存大小
return value.getByteCount();
}
};
File file = new File(CACHE_IMAGE_DIR);
if(!file.exists()) {
file.mkdirs();
}
}
private static void putCache(String key, Bitmap bm) {
lruCache.put(key, bm);
}
private static Bitmap getCache(String key) {
return lruCache.get(key);
}
public static void load(String url, OnBitmapCallback callback) {
if (callback == null) {
return;
}
Bitmap bitmap = null;
String pathName = CACHE_IMAGE_DIR + generateCacheName(url);
// 1.从内存获取
bitmap = getCache(pathName);
if (bitmap != null) {
callback.onSuccess(bitmap);
System.out.println("从内存拿~~~~~~~~~~~" + url);
return;
}
// 2.从本地存储获取
bitmap = getBitmapFromDisk(pathName);
if (bitmap != null) {
// 缓存到内存
putCache(pathName, bitmap);
callback.onSuccess(bitmap);
System.out.println("从本地磁盘拿~~~~~~~~~~~" + url);
return;
}
// 3.从网络下载
getBitmapFromRemote(url, callback);
}
public static void getBitmapFromRemote(final String url, final OnBitmapCallback callback) {
if (callback == null) {
return;
}
executor.submit(new Runnable() {
@Override
public void run() {
Bitmap bitmap = null;
HttpURLConnection conn = null;
InputStream inputStream = null;
FileOutputStream fos = null;
try {
URL uri = new URL(url);
conn = (HttpURLConnection) uri.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(3000);
conn.setReadTimeout(5000);
inputStream = conn.getInputStream();
if (conn.getResponseCode() == 200) {
bitmap = BitmapFactory.decodeStream(inputStream);
}
if (bitmap != null) {
String pathName = CACHE_IMAGE_DIR + generateCacheName(url);
fos = new FileOutputStream(pathName);
// 先写入到本地文件,再重新读取decode成Bitmap,能否一次操作两步?
// compress()方法保存好图片后,需要重新构造才能使用!!
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);
fos.close();
bitmap = getBitmapFromDisk(pathName);
putCache(pathName, bitmap);
callback.onSuccess(bitmap);
} else { // 最后如果从网络也获取不到那么就回调错误方法
callback.onFail(404);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if (conn != null) {
conn.disconnect();
}
}
}
});
}
public static Bitmap getBitmapFromDisk(String pathName) {
return BitmapFactory.decodeFile(pathName);
}
public static String generateCacheName(String str) {
return MD5.md5(str);
}
public static void clearCache() {
// 清除内存缓存
lruCache.evictAll();
// 清除磁盘缓存
File path = new File(CACHE_IMAGE_DIR);
if (path.exists()) {
if (path.isDirectory()) {
for (File f : path.listFiles()) {
f.deleteOnExit();
}
} else {
path.delete();
}
}
}
public static interface OnBitmapCallback {
void onSuccess(Bitmap bm);
void onFail(int errorCode);
}
}
定义了一个使用上面的工具来绑定ImageView的工具类:ImageBinder.java
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Looper;
import android.widget.ImageView;
public class ImageBinder {
public static void bind(final ImageView view, String url) {
// Handler使用了主线程的Looper,所以发送的消息也是在主线程里被处理
final Handler handler = new Handler(Looper.getMainLooper());
ImageUtils.load(url, new ImageUtils.OnBitmapCallback() {
@Override
public void onSuccess(final Bitmap bm) {
handler.post(new Runnable() {
@Override
public void run() {
view.setImageBitmap(bm);
}
});
}
@Override
public void onFail(int errorCode) {
}
});
}
}