Android_图片的三级缓存

本博文为子墨原创,转载请注明出处!
http://blog.csdn.net/zimo2013/article/details/15108267
/**
 * 
 * @author zimo2013
 * @see http://blog.csdn.net/zimo2013
 *
 */
public interface ICacheManager {
	public boolean addCacheBitmap(String key, Bitmap bitmap);
	public Bitmap getCacheBitmapByKey(String key);
	public void clear();
	public void remove(String key);
}
/**
 * 
 * @author zimo2013
 * @see http://blog.csdn.net/zimo2013
 *
 * LruCache缓存,由于指定了该缓存的最大值,可以方便管理内存中的缓存图片,
 * 关键的方法,为sizeOf() 和   entryRemoved()
 *
 */
class LruCacheManager implements ICacheManager{
	private static LruCacheManager manager;

	private static LruCache<String, Bitmap> lruCache;

	private LruCacheManager() {}

	/**
	 * 静态方法,得到SDCardCacheManager实例化对象
	 * 
	 * @return
	 */
	static LruCacheManager getManager(LruCache<String, Bitmap> cache) {
		if (manager == null) {
			manager = new LruCacheManager();
			lruCache = cache;
		}
		return manager;
	}

	public Bitmap getCacheBitmapByKey(String name) {
		return lruCache.get(name);
	}

	public boolean addCacheBitmap(String name, Bitmap bitmap) {
		if (name != null && bitmap != null) {
			lruCache.put(name, bitmap);
			return true;
        }
		return false;
	}

	@Override
	public void clear() {
		//待实现
	}

	@Override
	public void remove(String key) {
		//待实现
	}
}
/**
 * 
 * @author zimo2013
 * @see http://blog.csdn.net/zimo2013
 *
 * 在抛出内存溢出之前,回收SoftReference中中引用的对象
 *
 */
class SoftRefManager implements ICacheManager{
	private static SoftRefManager manager;
	
	private HashMap<String, SoftReference<Bitmap>> map;

	private SoftRefManager() {
		map = new HashMap<String, SoftReference<Bitmap>>();
	}
	/**
	 * 静态方法,得到SoftRefManager实例化对象
	 * @return
	 */
	static SoftRefManager getManager() {
		if(manager == null){
			manager = new SoftRefManager(); 
		}
		return manager;
	}
	
	/**
	 * 根据name找到软引用指向的对象
	 * @param name
	 * @return
	 */
	public Bitmap getCacheBitmapByKey(String name){
		Bitmap bitmap = null;
		SoftReference<Bitmap> softRef = map.get(name);
		if(softRef != null){
			bitmap = softRef.get();
			if(bitmap == null){
				map.remove(name);
			}
		}
		return bitmap;
	}
	/**
	 * 将制定的name-bitmap键值对添加至集合中
	 * @param name
	 * @param bitmap
	 */
	public boolean addCacheBitmap(String name, Bitmap bitmap){
		SoftReference<Bitmap> softRef = new SoftReference<Bitmap>(bitmap);
		map.put(name, softRef);
		return true;
	}
	@Override
	public void clear() {
		
	}
	@Override
	public void remove(String key) {
		
	}
}
/**
 * 
 * @author zimo2013
 * @see http://blog.csdn.net/zimo2013
 *
 * 管理SDCard image的缓存
 */
class SDCardCacheManager implements ICacheManager{
	private final static String TAG = "SDCardCacheManager";
	
	private List<CachedFile> cachedList;
	private long currentSize;		//当前缓存总大小
	
	private static SDCardCacheManager manager;
	private static File file;		//缓存文件目录 
	private static long CAPACITY;	//缓存文件总大小
	
	private static int LEVEL = 1;
	private static final int LEVEL_SAFE = 1;
	private static final int LEVEL_MAY_NOTSAFE = 2;
	private static final int LEVEL_NOTSAFE = 3;
	
	/**
	 * 静态方法,得到SDCardCacheManager实例化对象
	 * @return
	 */
	static SDCardCacheManager getManager() {
		if(manager == null){
			if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
				System.out.println("SDCard不存在或者尚未申请sdcard读写权限!");
			}else{
				System.out.println("sdcard:"+Constants.EXT_PATH);
				file = new File(Constants.CACHE_DIR);
				CAPACITY = Constants.CAPACITY;
				manager = new SDCardCacheManager();
			}
		}
		return manager;
	}
	/**
	 * 私有化的构造函数,完成缓存文件的遍历,初始化集合
	 */
	private SDCardCacheManager() {
		cachedList = new ArrayList<CachedFile>();
		//updateExternalLevel();
		if (!file.exists()) {
			file.mkdir();
			return;
		}
		for (File f : file.listFiles()) {	//循环遍历图片
			if (f.isFile()) {
				CachedFile cachedFile = new CachedFile(f.getName(), f.length(),
						f.lastModified());
				currentSize += f.length();
				cachedList.add(cachedFile);
			}
		}
	}

	/**
	 * 将指定的key-obj键值对保存至SDCard
	 */
	@Override
	public boolean addCacheBitmap(String key, Bitmap bitmap){
		if(LEVEL > LEVEL_MAY_NOTSAFE){
			System.out.println("外设存储不足, 暂不保存缓存");
			return false;
		}
		File f = new File(file, key);
		if (f.exists()) {	//如果该缓存文件已经存在
			return true;
		}
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(f);
			bitmap.compress(CompressFormat.PNG, 100, fos);
			currentSize += f.length();
			System.out.println("sdcard111"+f);
			CachedFile cachedFile = new CachedFile(key, f.length(),f.lastModified());
			cachedList.add(cachedFile);
			
			if(LEVEL > LEVEL_SAFE){
				updateExternalLevel();
			}
			if (currentSize > CAPACITY) {
				clear();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			if(fos != null){
				try {
					fos.close();
					System.out.println("sd流关闭成功");
					fos = null;
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return true;
	}

	/**
	 * 读取缓存目录中,指定name的bitmap对象
	 * @param name
	 * @return
	 */
	@Override
	public Bitmap getCacheBitmapByKey(String key) {
		Bitmap bitmap = null;
		for (CachedFile cachedFile : cachedList) {
			if (cachedFile.getName().equals(key)) {
				File f = new File(file, key);
				if(f.exists()){
					f.setLastModified(System.currentTimeMillis());	//更新file时间
					bitmap = BitmapFactory.decodeFile(f.getAbsolutePath());
					
					System.out.println("sdcard命中:"+key);
				}
				return bitmap;
			}
		}
		return bitmap;
	}

	@Override
	public void remove(String key) {
		if(key == null){
			System.out.println("key不能为空");
			return;
		}
		//待开发
	}
	
	/**
	 * 清理缓存,当缓存容量超过指定CAPACITY时执行
	 */
	@Override
	public void clear() {
		Collections.sort(cachedList);
		int end = cachedList.size();
		int start = end*2 / 3; // 清理最久未被使用的1/3
		ListIterator<CachedFile> it = cachedList.listIterator(start);
		while(it.hasNext()){
			CachedFile cachedFile = it.next();
			System.out.println("清理文件"+cachedFile.getName());
			new File(file, cachedFile.getName()).delete();
			currentSize -= cachedFile.getLength();
			it.remove();
		}
	}
	public Object getCacheFileByKey(String key) {
		Object obj = null;
		for (CachedFile cachedFile : cachedList) {
			if (cachedFile.getName().equals(key)) {
				return cachedFile;
			}
		}
		return obj;
	}
	/**
	 * 更新外部存储剩余容量等级<br/>
	 * LEVEL_SAFE = 1 <br/>
	 * LEVEL_MAY_NOTSAFE = 2 <br/>
	 * LEVEL_NOTSAFE = 3<br/>
	 */
	public void updateExternalLevel(){
		StatFs statFs = new StatFs(Constants.EXT_PATH);
		int availBlock = statFs.getAvailableBlocks();
		int blockSize = statFs.getBlockSize();
		long availByte = availBlock*blockSize;
		
		Log.i(TAG, "availByte = "+availByte);
		
		if(availBlock*blockSize > 1024*1024*30){		//30M
			LEVEL = LEVEL_SAFE;
		}else if(availBlock*blockSize > 1024*1024*5){	//5M
			LEVEL = LEVEL_MAY_NOTSAFE;
		}else{
			LEVEL = LEVEL_NOTSAFE;
		}
	}
}
/**
 * 
 * @author zimo2013
 * @see http://blog.csdn.net/zimo2013
 *
 */
public class AppCacheManager implements ICacheManager {
	private final static String TAG = "AppCacheManager";
	
	private static ICacheManager manager;
	/**
	 * 在使用sdcard时,应该首先判断sdcard是否存在且挂载可用,如果使用只需要判断 if(sdManager != null); 
	 */
	private static SDCardCacheManager sdManager;
	private static SoftRefManager refManager;
	private static LruCacheManager lruManager;
	private AppCacheManager() {
	}

	public static ICacheManager getManager() {
		if (manager == null) {
			manager = new AppCacheManager();

			sdManager = SDCardCacheManager.getManager();
			refManager = SoftRefManager.getManager();
			lruManager = LruCacheManager.getManager(new LruCacheList(Constants.LRU_MAXSIZE));
			// 相应manager缓存管理对象
		}
		return manager;
	}

	private static class LruCacheList extends LruCache<String, Bitmap> {
		public LruCacheList(int maxSize) {
			super(maxSize);
		}

		@Override
		protected int sizeOf(String key, Bitmap value) {
			return value.getRowBytes() * value.getHeight();
		}

		@Override
		protected void entryRemoved(boolean evicted, String key,
				Bitmap oldValue, Bitmap newValue) {
			if (evicted) {
				LogUtil.i(TAG, "缓存被挤出:"+key);
				//如果sdCard存在,写入sdCard
				if(sdManager != null){	
					sdManager.addCacheBitmap(key, oldValue);
				}
				// 2.添加至软引用集合
				refManager.addCacheBitmap(key, oldValue);
			}
		}
	}

	/**
	 * 将key-obj键值对存入
	 */
	@Override
	public boolean addCacheBitmap(String key, Bitmap bitmap) {
		if (key == null || bitmap == null) {
			System.out.println("key=null || obj=null");
			return false;
		}
		if(sdManager != null){	//如果sdcard存在可用,存入sdcard
			sdManager.addCacheBitmap(key, bitmap);
		}
		lruManager.addCacheBitmap(key, bitmap);
		return true;
	}

	/**
	 * 得到缓存对象根据key,如果返回为null需要访问网络获取数据
	 */
	@Override
	public Bitmap getCacheBitmapByKey(String key) {
		if(key == null){
			return null;
		}
		Bitmap bitmap = lruManager.getCacheBitmapByKey(key);
		if (bitmap == null) {
			bitmap = refManager.getCacheBitmapByKey(key);
			if (bitmap==null && sdManager!=null) {	//从sdcard中取数据
				bitmap = sdManager.getCacheBitmapByKey(key);
			}
		}
		if (bitmap != null) {
			lruManager.addCacheBitmap(key, bitmap);
		}
		return bitmap;
	}

	@Override
	public void clear() {
		lruManager.clear();
		refManager.clear();
		
		if(sdManager != null){
			sdManager.clear();
		}
	}

	@Override
	public void remove(String key) {
		lruManager.remove(key);
		refManager.remove(key);
		
		if(sdManager != null){
			sdManager.remove(key);
		}
	}
}
/**
 * 缓存文件bean
 *
 */
public class CachedFile implements Comparable<CachedFile> {
	private String name;
	private long length;
	private long modTime;
	
	public CachedFile() {
	}
	public CachedFile(String name, long length, long modTime) {
		this.name = name;
		this.length = length;
		this.modTime = modTime;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public long getLength() {
		return length;
	}
	public void setLength(long length) {
		this.length = length;
	}
	public long getModTime() {
		return modTime;
	}
	public void setModTime(long modTime) {
		this.modTime = modTime;
	}
	@Override
	public int compareTo(CachedFile another) {
		if(this.modTime > another.modTime)
			return -1;
		return 1;
	}
}
public class Constants {
	
	public final static String EXT_PATH = Environment
			.getExternalStorageDirectory().getAbsolutePath();
	public final static int LRU_MAXSIZE = 8 * 1024 * 1024;
	public final static int CAPACITY = 10 * 1024 * 1024;
	public final static String CACHE_DIR = EXT_PATH + "/cache";
}


你可能感兴趣的:(android,bitmap,cache,SoftReference,LruCache)