LruCache

来源:互联网 发布:插画师dorami辞软件 编辑:程序博客网 时间:2024/06/05 16:34

当应用程序UI界面需要显示大量的图片,比如:使用ListView, GridView 或者 ViewPager 这样的组件,随着滑动屏幕图片不断增加,最终会导致OOM,原因如下:

1.Android虚拟机默认为每个App分配16MB的内存空间,不同的真机厂商可以对此值进行设置;
2.Android 系统在加载图片时是解析每一个像素的信息,再把每一个像素全部保存至内存中;
3.一张图片(BitMap)占用的内存=图片长度图片宽度单位像素占用的字节数; 注:图片长度和图片宽度的单位是像素;例如:一张1920x1080的JPG图片,在Android 系统中是以ARGB8888格式储存的,即一个像素需占用4个字节,图片的大小=1920x1080x4=8M。

为了保证内存的使用始终维持在一个合理的范围,通常会把被移除屏幕的图片进行回收处理。此时垃圾回收器也会认为你不再持有这些图片的引用,从而对这些图片进行GC操作。用这种思路来解决问题是非常好的,可是为了能让程序快速运行,在界面上迅速地加载图片,你又必须要考虑到某些图片被回收之后,用户又将它重新滑入屏幕这种情况。这时重新去加载一遍刚刚加载过的图片无疑是性能的瓶颈,你需要想办法去避免这个情况的发生。此时可使用缓存技术解决这个问题,它可以让组件快速地重新加载和处理图片。

目前常用的缓存算法是LRU算法,它的核心思想是优先淘汰那些近期最少使用的缓存对象;采用LRU算法缓存有两种:LruCache(内存缓存)和DiskLruCache(磁盘缓存),其中加载图片时通常是首先从内存缓存中加载,然后是磁盘缓存,最后是网络请求。

如LruCache加载图片时,它会把使用的对象以强引用储存在 LinkedHashMap 中,当储存的缓存值达到我们设置的容量后,会移除最近最少使用的对象,然后再添加新的对象。

private LruCache<String,Bitmap> mMemoryCache;public MemoryCacheUtils(){    //获取当前进程的可用内存,单位是KB;    int maxMemory = (int)(Runtime.getRuntime().maxMemory()/1024);    //设置缓存的总容量大小为当前进程可用内存的1/8,单位是KB;    int cacheSize = maxMemory/8;    mMemoryCache = new LruCache<String,Bitmap>(cacheSize){       @Override       //此方法用于计算每张图片的大小,默认返回值是1,这里设置返回该图片的大小单位是KB;       protected int sizeOf(String key, Bitmap bitmap) {          return bitmap.getByteCount()/1024;       }    };}public void addBitmapToMemoryCache(String key,Bitmap bitmap){   //添加缓存对象   mMemoryCache.put(key, bitmap);}public Bitmap getBitmapFormMemoryCache(String key){   //获取缓存对象   return mMemoryCache.get(key);}public void remnove(String key){   //移除特定的缓存对象   mMemoryCache.remove(key);}

对于上面的代码设置的容量是当前进程的可用内存的1/8,单位是KB,而sizeOf方法则是计算Bitmap对象的大小,这里将其单位也转化为KB。在一些特殊情况下需要重写LruCache的entryRemove方法,因为LruCache移除缓存时会调用entryRemove方法,因此可在此方法完成一些资源回收工作。当前页面不可以见时,即使前期添加了缓存如调用addBitmapToMemoryCache,后续在返回该页面时仍然需要重新加载缓存,否则获取缓存时将返回null,因此LruCache通常用于在同个页面某些图片需要经常调用的情景中,如Listview,GridView,ViewPager等。

参考:

Android高效加载大图、多图解决方案,有效避免程序OOM
Android中图片的三级缓存