使用三级缓存解决内存溢出

来源:互联网 发布:甲骨文软件测试面试 编辑:程序博客网 时间:2024/05/19 21:17

在Android开发的过程中,涉及到图片通常容易产生内存溢出的问题,

使用三级缓存的思路可以比较好的解决这个问题。

如下图所示为三级缓存的示意图,第一级为内存缓存,第二级为软引用缓存,第三级为文件缓存

它们的特点如下图所示。

image

 

类图如下图所示,Cache为缓存的接口,定义了缓存必须实现的方法,其他的类均实现了Cache接口。ThreeLevelCache包含有

MemoryCache、SoftReferenceCache和FileCache。

 

image

Cache接口

public interface Cache {public void put(String key,Bitmap bitmap);//存入public Bitmap get(String key);//取出public boolean isExist(String key);//是否存在public void clear();//清空}

内存缓存MemoryCache

/** * 内存缓存,设置大小限制,当超过限制,将最近最久未使用的一项移出 * @author huangbei * */public class MemoryCache implements Cache {private  Map<String, Bitmap> cache ;private Cache softCache;//内存缓存所占的字节,初始为0private long size ;// 内存缓存当中所占字节的最大限制private long limit ;public MemoryCache(Cache softCache){//设置默认限制为最大运行内存的八分之一setLimit(Runtime.getRuntime().maxMemory() / 8);  size=0;this.softCache= softCache;// 放入缓存时是个同步操作  // LinkedHashMap构造方法的最后一个参数true代表这个map里的元素将按照最近使用次数由少到多排列,即LRU  // 这样的好处是如果要将缓存中的元素替换,则先遍历出最近最少使用的元素来替换以提高效率  cache = Collections.synchronizedMap(new LinkedHashMap<String, Bitmap>(10, 1.5f, true));}public void setLimit(long limit){this.limit=limit;}@Overridepublic void put(String key, Bitmap bitmap) {this.cache.put(key, bitmap);if(!checkSize(bitmap)){remove();}}@Overridepublic Bitmap get(String key) {return cache.get(key);}@Overridepublic boolean isExist(String key) {return cache.containsKey(key);}@Overridepublic void clear() {cache.clear(); }//检查添加的图片是否会超过限制private boolean checkSize(Bitmap bitmap){long bitsize=BitmapUtil.getSizeInBytes(bitmap);if((size+bitsize)<=limit){return true;}else{return false;}}//移除掉超过内存限制的图片private void remove(){Iterator<Entry<String, Bitmap>> iter = cache.entrySet().iterator();  while (iter.hasNext()) {  Entry<String, Bitmap> entry = iter.next();  size -= BitmapUtil.getSizeInBytes(entry.getValue());softCache.put(entry.getKey(), entry.getValue());iter.remove();if (size <= limit)  break;  }}}

软引用缓存SoftReferenceCache

/** * 软引用缓存,不设置大小限制,内存不够,系统自动释放 * @author huangbei * */public class SoftReferenceCache implements Cache {//软引用缓存private  Map<String, SoftReference<Bitmap>> cache;public SoftReferenceCache(){cache = new HashMap<String, SoftReference<Bitmap>>();}@Overridepublic void put(String key, Bitmap bitmap) {cache.put(key, new SoftReference<Bitmap>(bitmap));}@Overridepublic Bitmap get(String key) {return cache.get(key).get();}@Overridepublic boolean isExist(String key) {if(cache.containsKey(key)&&cache.get(key).get()!=null)return true;elsereturn false;}@Overridepublic void clear() {cache.clear(); }}

文件缓存FileCache

/** * 文件缓存,图片存于文件当中,不设置大小限制,避免重复下载,节省流量 * @author huangbei * */public class FileCache implements Cache{    private String cashe_dir="";        private File cacheDir;  //图片存储的路径        public FileCache(Context context) {        if (android.os.Environment.getExternalStorageState()                .equals(android.os.Environment.MEDIA_MOUNTED)){             cacheDir = new File(android.os.Environment.getExternalStorageDirectory(), cashe_dir);        }else{            cacheDir = context.getCacheDir();        }        if (!cacheDir.exists())            cacheDir.mkdirs();    }@Overridepublic void put(String key, Bitmap bitmap) {File f = new File(cacheDir, key);        if(!f.exists()){            try {                f.createNewFile();            } catch (IOException e) {                e.printStackTrace();            }        }        BitmapUtil.saveBitmap(f, bitmap);}@Overridepublic Bitmap get(String key) {File f = new File(cacheDir, key);        if (f.exists()){            return BitmapUtil.decodeFile(f);        }else{        return null;        } }@Overridepublic boolean isExist(String key) {File f = new File(cacheDir, key);        if (f.exists()){            return true;        }else{        return false;        } }@Overridepublic void clear() {File[] files = cacheDir.listFiles();        for (File f : files)            f.delete();}}

三级缓存 ThreeLevelCache

public class ThreeLevelCache implements Cache{private Cache memoryCache;private Cache softCache;private Cache fileCache;private ThreeLevelCache cache; private ThreeLevelCache(Context context){this.softCache=new SoftReferenceCache();this.fileCache=new FileCache(context);this.memoryCache=new MemoryCache(softCache);}public ThreeLevelCache newInstance(Context context){if(cache==null){    cache=new ThreeLevelCache(context);}return cache;}@Overridepublic void put(String key, Bitmap bitmap) {        this.fileCache.put(key, bitmap);        this.memoryCache.put(key, bitmap);}@Overridepublic Bitmap get(String key) {if(memoryCache.isExist(key)){return memoryCache.get(key);}else if(softCache.isExist(key)){return softCache.get(key);}else if(fileCache.isExist(key)){return fileCache.get(key);}else{return null;}}@Overridepublic boolean isExist(String key) {return memoryCache.isExist(key)||softCache.isExist(key)||fileCache.isExist(key);}@Overridepublic void clear() {memoryCache.clear();softCache.clear();fileCache.clear();}}

其中所用到的一些关于图片的方法存于类BitmapUtil中

public class BitmapUtil {//图片所占的内存大小public static long getSizeInBytes(Bitmap bitmap) {  if (bitmap == null){ return 0;  }return bitmap.getRowBytes() * bitmap.getHeight();  }//将图片存入文件当中public static boolean saveBitmap(File file, Bitmap bitmap){        if(file == null || bitmap == null)            return false;        try {            BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));            return bitmap.compress(CompressFormat.JPEG, 100, out);        } catch (FileNotFoundException e) {            e.printStackTrace();            return false;        }    }// decode这个图片并且按比例缩放以减少内存消耗,虚拟机对每张图片的缓存大小也是有限制的  public static Bitmap decodeFile(File f) {      try {      // decode image size      BitmapFactory.Options option = new BitmapFactory.Options();      option.inJustDecodeBounds = true;      BitmapFactory.decodeStream(new FileInputStream(f), null, option);      // Find the correct scale value. It should be the power of 2.      final int REQUIRED_SIZE = 100;      int width_tmp = option.outWidth, height_tmp = option.outHeight;      int scale = 1;      while (true) {      if (width_tmp / 2 < REQUIRED_SIZE  || height_tmp / 2 < REQUIRED_SIZE){    break;      }    width_tmp /= 2;      height_tmp /= 2;      scale *= 2;      }      // decode with inSampleSize      BitmapFactory.Options option2 = new BitmapFactory.Options();      option2.inSampleSize = scale;      return BitmapFactory.decodeStream(new FileInputStream(f), null, option2);      } catch (FileNotFoundException e) {      e.printStackTrace();    return null;    }  }}
0 0
原创粉丝点击