文章来自:http://keegan-lee.diandian.com/post/2012-12-06/40047548955
多写了点注释而已,没有其他的变化,只有两级,硬引用和软引用,感觉已经够了吧,没用到弱引用
public class ImageFileCache { // 目录名称 private static final String CACHDIR = "ImgCach"; // 图片缓存后缀 private static final String WHOLESALE_CONV = ".cach"; // 10mb private static final int MB = 1024 * 1024; // 10张图片 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) { // bitmap == null直接返回 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); // 将该bitmap写入到outStream输出流 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) { // 以路径dirPath构造File实例 File dir = new File(dirPath); // 图片文件数组, dir不是路径时,返回null File[] files = dir.listFiles(); // if (files == null) { return true; } // sd卡的存储状态必须可读可写,否则返回false if (!android.os.Environment.getExternalStorageState().equals( android.os.Environment.MEDIA_MOUNTED)) { return false; } int dirSize = 0; for (int i = 0; i < files.length; i++) { // 判断该文件名是否存在WHOLESALE_CONV后缀 // 存在则获取文件长度,长度为0说明文件不存在 if (files[i].getName().contains(WHOLESALE_CONV)) { dirSize += files[i].length(); } } // 如果总文件长度大于CACHE_SIZE * MB(10mb)|| 当前 freeSpaceOnSd() < 10mb 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(); } } } // 如果sd卡剩余空间 <= 10mb 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查询文件系统相关的信息。 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; // getExternalStorageState() 获得当前外部储存媒体的状态。 // MEDIA_MOUNTED 存储媒体已经挂载,并且挂载点可读/写。 boolean sdCardExist = Environment.getExternalStorageState().equals( android.os.Environment.MEDIA_MOUNTED); // 判断sd卡是否存在 if (sdCardExist) { // getExternalStorageDirectory() 获取外部存储媒体目录 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 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) { // 通过ActivityManager获取应用的可用内存大小,单位mb 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(); } }
package bitmap.cache; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.util.Log; 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 class GetBitmap { /*** 获得一张图片,从三个地方获取,首先是内存缓存,然后是文件缓存,最后从网络获取 ***/ public static Bitmap getBitmap(String url) { // 从内存缓存中获取图片 Bitmap result = TestApp.memoryCache.getBitmapFromCache(url); if (result == null) { // 文件缓存中获取 result = TestApp.fileCache.getImage(url); if (result == null) { // 从网络获取 result = ImageGetFromHttp.downloadBitmap(url); if (result != null) { TestApp.fileCache.saveBitmap(result, url); TestApp.memoryCache.addBitmapToCache(url, result); } } else { // 添加到内存缓存 TestApp.memoryCache.addBitmapToCache(url, result); } } return result; } }
就这样了啊,要记得用线程加载啊!否则就。。。。。。。。。。。你懂的