Android网络图片缓存,,获取一张图片,从三个地方
Android网络图片缓存,,获取一张图片,从三个地方
获取一张图片,从三个地方进行获取,首先是内存缓存,然后是文件缓存,最后才从网络中获取。```java
//内存缓存
public class ImageMemoryCache {
/**
从内存读取数据速度是最快的,为了更大限度使用内存,这里使用了两层缓存。 硬引用缓存不会轻易被回收,用来保存常用数据,不常用的转入软引用缓存。*/
privatestatic finalint SOFT_CACHE_SIZE = 15;// 软引用缓存容量
privatestatic LruCache<String, Bitmap> mLruCache; // 硬引用缓存
privatestatic 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
protectedint sizeOf(String key, Bitmap value) {
if (value !=null)
return value.getRowBytes() * value.getHeight();
else
return 0;
}
@Override
protectedvoid 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) {
privatestatic final long serialVersionUID = 6040103833179403725L;
@Override
protectedboolean removeEldestEntry(
Entry<String, SoftReference<Bitmap>> eldest) {
if (size() >SOFT_CACHE_SIZE) {
returntrue;
}
returnfalse;
}
};
}
/**
从缓存中获取图片*/
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);
}
}
}
returnnull;
}
/**
添加图片到缓存*/
publicvoid addBitmapToCache(String url, Bitmap bitmap) {
if (bitmap !=null) {
synchronized (mLruCache) {
mLruCache.put(url, bitmap);
}
}
}
publicvoid 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 finalint CACHE_SIZE = 10;privatestaticfinalintFREE_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;
```
用户点评