在一个app中,图片资源是处处存在的,加载图片的流程一般是:

1 先从缓存中读取
2 若缓存中不存在,从SD卡中读取
3 若SD卡中也不存在,则从服务器拉取

后两个步骤纯碎属于业务逻辑,暂且不表,这里来看一下手Q使用的图片缓存管理策略。
说到缓存管理,首先谈一下java中的强引用和弱引用

  • 强引用:最普遍的引用,若一个对象具有强引用,那么GC绝不会回收它。如A a = new A()
  • 弱引用: 弱引用又分为以下三类:
    • 软引用(SoftReference): 这类引用只有当内存空间不足GC才会回收它
    • 弱引用(WeakReference): 这类引用拥有更短的生命周期,GC扫描过程中一旦发现了此类引用,不管当前内存是否足够,立即回收
    • 虚引用(PhantomRefence): 这类引用并不会决定对象的生命周期,如果一个对象仅持有虚引用,则任何时刻都可能被回收

下面来看看这样一个图片缓存类,为了更大限度使用缓存,它使用了强引用缓存(强引用)和弱引用缓存(弱引用)双重缓存,强引用缓存不会轻易被回收,用来保存常用数据,不常用的转入弱引用缓存。**

ImageCache.javapublic class ImageCache {private static final String TAG = "ImageCache";//CustomLruCache是一个继承了LruCache的继承类,它代表强引用缓存,它的缓存大小一般由业务方提供private CustomLruCache<String, Drawable> mMemoryCache;// Default memory cache size//这里设置的是弱引用缓存以及它所占据的空间大小private static final int DEFAULT_MEM_CACHE_SIZE = 5; // 5MBprivate final HashMap<String, WeakReference<Drawable>> mRefCache = new HashMap<String, WeakReference<Drawable>>();public ImageCache(int memSize) {memSize = Math.max(memSize, DEFAULT_MEM_CACHE_SIZE);QLog.d(TAG, "Memory cache size = " + memSize + "MB");mMemoryCache = new CustomLruCache<String, Drawable>(memSize * 1024 * 1024) {//这里重写了LruCache的sizeOf方法,来计算每个图片资源所占用内存的字节数@Overrideprotected int sizeOf(String key, Drawable drawable) {if (drawable instanceof BitmapDrawable) {Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();if (bitmap != null) {//若是bitmap位图则直接计算它的大小return bitmap.getRowBytes() * bitmap.getHeight();}return 0;} else if (drawable instanceof AnimationDrawable) {//若是逐帧动画,则首先获取它所有的帧数,再计算总共的大小AnimationDrawable anim = (AnimationDrawable) drawable;int count = anim.getNumberOfFrames();int memSize = 0;for (int i = 0; i < count; i++) {Drawable dr = anim.getFrame(i);if (dr instanceof BitmapDrawable) {Bitmap bitmap = ((BitmapDrawable) dr).getBitmap();if (bitmap != null) {memSize += bitmap.getRowBytes() * bitmap.getHeight();}}}return memSize;}return 0;}};}//从缓存中获取图片public Drawable getImageFromMemCache(String key) {Drawable memDrawable = null;if (mMemoryCache != null) {//首先从强引用缓存中获取图片,若找到的话,把元素移动到CustomLruCache的最后面,从而保证它在LRU算法中最后被删除?//疑问,其实LinkedHashMap本身就存在LRU的算法机制,因此,get的时候,会自动移入到队列尾部memDrawable = mMemoryCache.remove(key);if (memDrawable != null) {memDrawable = memDrawable.getConstantState().newDrawable();mMemoryCache.put(key, memDrawable);return memDrawable;}}//强引用缓存中没有找到,开始在弱引用缓存中查找WeakReference<Drawable> ref = mRefCache.get(key);if (ref != null) {//若找到的话,这里是否添加一步,将其从弱引用缓存移入强引用缓存中比较好memDrawable = ref.get();if (memDrawable == null) {mRefCache.remove(key);}}return memDrawable;}//添加图片到缓存,这里不理解为什么要向强引用缓存和弱引用缓存都要添加一份public void addImageToCache(String data, Drawable drawable) {// Add to memory cacheif (mMemoryCache != null && mMemoryCache.get(data) == null) {mMemoryCache.put(data, drawable);mRefCache.put(data, new WeakReference<Drawable>(drawable));}}//从缓存中删除资源public void removeImageFromCache(String data) {if (mRefCache != null) {mRefCache.remove(data);}if (mMemoryCache != null) {mMemoryCache.remove(data);}}public Drawable getImageFromDiskCache(String pathName) {// TODO 暂不支持disk cachereturn null;}public void clearCaches() {// mDiskCache.clearCache();mMemoryCache.evictAll();mRefCache.clear();}
}

整个缓存策略是使用弱引用缓存和强引用缓存配合使用,并结合LRUCache,在尽可能地利用缓存的基础上,也大大提高了缓存命中率。我个人觉得这个类有改进的地方,比如,当LRUCache在移除元素的时候,默认是直接删除掉。这里更好的方式是重写LRUCache的entryRemoved方法,使得强引用缓存满的时候,会根据LRU算法将最近最久没有被使用的图片自动移入弱引用缓存,如下:

  mMemoryCache = new CustomLruCache<String, Drawable>(memSize * 1024 * 1024) {//这里重写了LruCache的sizeOf方法,来计算每个图片资源所占用内存的字节数@Overrideprotected int sizeOf(String key, Drawable drawable) {.........}当强引用缓存满时,会自动调用这个方法,这时候,将移除的元素添加到弱引用缓存中@Overrideprotected void entryRemoved(boolean evicted, String key, Drawable oldDrawable, Drawable newDrawable) {if (oldDawable != null) {mRefCache.put(data, new WeakReference<Drawable>(oldDawable));}}};

Android图片缓存管理相关推荐

  1. Android之图片缓存管理

    如果每次加载同一张图片都要从网络获取,那代价实在太大了.所以同一张图片只要从网络获取一次就够了,然后在本地缓存起来,之后加载同一张图片时就从缓存中加载就可以了.从内存缓存读取图片是最快的,但是因为内存 ...

  2. Android 图片缓存之内存缓存技术LruCache,软引用

    Android 图片缓存之内存缓存技术LruCache,软引用

  3. Android图片缓存之Lru算法

    前言: 上篇我们总结了Bitmap的处理,同时对比了各种处理的效率以及对内存占用大小.我们得知一个应用如果使用大量图片就会导致OOM(out of memory),那该如何处理才能近可能的降低oom发 ...

  4. Android图片缓存框架Glide

    Android图片缓存框架Glide Glide是Google提供的一个组件.它具有获取.解码和展示视频剧照.图片.动画等功能.它提供了灵活的API,帮助开发者将Glide应用在几乎任何网络协议栈中. ...

  5. android图片缓存,直接应用项目中的Android图片缓存技术

    前不久搞的Android图片缓存,刚开始引入开源的框架,用着还行,但是在开发中遇到问题,就比如universal-image-loader-1.9.5.jar这个框架吧,在加载图片的时候自定义imag ...

  6. Android 图片缓存机制

    1.采用线程池  2.内存缓存+文件缓存  3.内存缓存中网上很多是采用SoftReference来防止堆溢出,这儿严格限制只能使用最大JVM内存的1/4  4.对下载的图片进行按比例缩放,以减少内存 ...

  7. android 图片缓存工具类,Android工具类系列-Glide图片缓存与圆角

    Glide的图片缓存和清除图片缓存 public class GlideCacheUtil { private static GlideCacheUtil inst; public static Gl ...

  8. android 图片缓存

    一.Picasso https://github.com/square/picasso Picasso是Square公司开源的一个Android平台上的图片加载框架,简单易用,一句话搞定项目中的图片加 ...

  9. Android图片缓存框架 - Fresco的GenericDraweeHierarchy (五)

    目录 1.Fresco 简介 2. Fresco 文档 3. Fresco开发步骤 4. Fresco加载图片6种方式 5. Drawees xm属性设置 6 Fresco实现圆角或圆形图片 7. D ...

最新文章

  1. ORACLE初次安装自动安装软件包
  2. iphone popViewControllerAnimated后刷新原先的表格
  3. 如何在Node JS中卸载NPM模块?
  4. openssl md5算法 —— Linux下(字符串加密、文件加密)
  5. Convert PLY to VTK Using PCL 1.6.0 or PCL 1.8.0 使用PCL库将PLY格式转为VTK格式
  6. 苹果宣布创立欧洲首个iOS开发中心
  7. *ctf 逆向math题解
  8. 2108889队2021年数学建模美赛C题花絮视频!
  9. django-vue-admin前端设置后台接口地址为127.0.0.1产生跨域问题解决办法
  10. 商务英语如何利用计算机思维,如何更好的运用商务英语
  11. 给创业者的30条建议
  12. android 查询wifi信息的类,Android 获取wifi信息
  13. 黄聪:Wordpress程序Mysql查询导致CPU100%,页面错误增量飙高解决方案
  14. JS 新浪API获取IP归属地
  15. AutoCAD 2019 for mac汉化版
  16. win10下安装deepin双系统教程
  17. 【基于物理的渲染(PBR)白皮书】(三)迪士尼原则的BRDF与BSDF相关总结
  18. IE地址栏的最大长度
  19. contos7 配置 python3环境 支持微信公众号开发
  20. 女测试工程师的成长(1-4)

热门文章

  1. 如何把antlr4融合到编译器项目中使用
  2. 宝塔安装MongoDB
  3. Python numpy列表加负号
  4. AutoLeaders控制组—外围电阻大小与外部供电电压确定设计方案(本次报告的名称)
  5. axios 拦截器实现原理
  6. 二、Python3自动化运维——IP地址处理模块IPy
  7. Spring Cloud Stream中文翻译
  8. [高级项目管理师]项目立项、招投标、合同与采购管理
  9. prim算法适用条件_prim算法
  10. C#已知三点求圆方程算法