獲取一張圖片,從三個地方進行獲取,首先是內存緩存,而後是文件緩存,最後才從網絡中獲取。android
//內存緩存算法
public class ImageMemoryCache {緩存
/**網絡
* 從內存讀取數據速度是最快的,爲了更大限度使用內存,這裏使用了兩層緩存。 硬引用緩存不會輕易被回收,用來保存經常使用數據,不經常使用的轉入軟引用緩存。less
*/ide
private static final int SOFT_CACHE_SIZE = 15; // 軟引用緩存容量url
private static LruCache<String, Bitmap> mLruCache; // 硬引用緩存spa
private static LinkedHashMap<String, SoftReference<Bitmap>> mSoftCache; // 軟引用緩存code
public ImageMemoryCache(Context context) {orm
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();
}
}
//文件緩存,緩存到SD卡上
public class ImageFileCache {
private static final String CACHDIR = "ImgCach";
private static final String WHOLESALE_CONV = ".cach";
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() {
//清理文件緩存
removeCache(getDirectory());
}
/** 從緩存中獲取圖片 **/
public Bitmap getImage(final String url) {
final String path = getDirectory() + "/" + 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(Bitmap bm, String url) {
if (bm == null) {
return;
}
//判斷sdcard上的空間
if (FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {
//SD空間不足
return;
}
String filename = convertUrlToFileName(url);
String dir = getDirectory();
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(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()) {
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() <= 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() {
StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
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() {
String dir = getSDPath() + "/" + CACHDIR;
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 "";
}
}
/**
* 根據文件的最後修改時間進行排序
*/
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;
}
}
}
}
//從網絡加載圖片
public class ImageGetFromHttp {
private static final String LOG_TAG = "ImageGetFromHttp";
public static Bitmap downloadBitmap(String url) {
final HttpClient client = new DefaultHttpClient();
final HttpGet getRequest = new HttpGet(url);
try {
HttpResponse response = client.execute(getRequest);
final int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.w(LOG_TAG, "Error " + statusCode + " while retrieving bitmap from " + url);
return null;
}
final HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream inputStream = null;
try {
inputStream = entity.getContent();
FilterInputStream fit = new FlushedInputStream(inputStream);
return BitmapFactory.decodeStream(fit);
} finally {
if (inputStream != null) {
inputStream.close();
inputStream = null;
}
entity.consumeContent();
}
}
} catch (IOException e) {
getRequest.abort();
Log.w(LOG_TAG, "I/O error while retrieving bitmap from " + url, e);
} catch (IllegalStateException e) {
getRequest.abort();
Log.w(LOG_TAG, "Incorrect URL: " + url);
} catch (Exception e) {
getRequest.abort();
Log.w(LOG_TAG, "Error while retrieving bitmap from " + url, e);
} finally {
client.getConnectionManager().shutdown();
}
return null;
}
/*
* An InputStream that skips the exact number of bytes provided, unless it reaches EOF.
*/
static class FlushedInputStream extends FilterInputStream {
public FlushedInputStream(InputStream inputStream) {
super(inputStream);
}
@Override
public long skip(long n) throws IOException {
long totalBytesSkipped = 0L;
while (totalBytesSkipped < n) {
long bytesSkipped = in.skip(n - totalBytesSkipped);
if (bytesSkipped == 0L) {
int b = read();
if (b < 0) {
break; // we reached EOF
} else {
bytesSkipped = 1; // we read one byte
}
}
totalBytesSkipped += bytesSkipped;
}
return totalBytesSkipped;
}
}
}
//=============================獲取圖片========================================
/*** 得到一張圖片,從三個地方獲取,首先是內存緩存,而後是文件緩存,最後從網絡獲取 ***/
public Bitmap getBitmap(String url) {
// 從內存緩存中獲取圖片
Bitmap result = memoryCache.getBitmapFromCache(url);
if (result == null) {
// 文件緩存中獲取
result = fileCache.getImage(url);
if (result == null) {
// 從網絡獲取
result = ImageGetFromHttp.downloadBitmap(url);
if (result != null) {
fileCache.saveBitmap(result, url);
memoryCache.addBitmapToCache(url, result);
}
} else {
// 添加到內存緩存
memoryCache.addBitmapToCache(url, result);
}
}
return result;
}