文档章节

Android LruCache 缓存图片

娶到笨笨
 娶到笨笨
发布于 2014/04/23 09:21
字数 1541
阅读 61
收藏 4

使用图片缓存技术

在 你应用程序的UI界面加载一张图片是一件很简单的事情,但是当你需要在界面上加载一大堆图片的时候,情况就变得复杂起来。在很多情况下,(比如使用 ListView, GridView 或者 ViewPager 这样的组件),屏幕上显示的图片可以通过滑动屏幕等事件不断地增加,最终导致OOM。

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

这个时候,使用内存缓存技术可以很好的解决这个问题,它可以让组件快速地重新加载和处理图片。下面我们就来看一看如何使用内存缓存技术来对图片进行缓存,从而让你的应用程序在加载很多图片的时候可以提高响应速度和流畅性。

内存缓存技术对那些大量占用应用程序宝贵内存的图片提供了快速访问的方法。其中最核心的类是LruCache (此类在android-support-v4的包中提供) 。这个类非常适合用来缓存图片,它的主要算法原理是把最近使用的对象用强引用存储在 LinkedHashMap 中,并且把最近最少使用的对象在缓存值达到预设定值之前从内存中移除。

在过去,我们经常会使用一种非常流行的内存缓存技术的实现,即软引用或弱引用 (SoftReference or WeakReference)。但是现在已经不再推荐使用这种方式了,因为从 Android 2.3 (API Level 9)开始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象,这让软引用和弱引用变得不再可靠。另外,Android 3.0 (API Level 11)中,图片的数据会存储在本地的内存当中,因而无法用一种可预见的方式将其释放,这就有潜在的风险造成应用程序的内存溢出并崩溃。

为了能够选择一个合适的缓存大小给LruCache, 有以下多个因素应该放入考虑范围内,例如:

  • 你的设备可以为每个应用程序分配多大的内存?

  • 设备屏幕上一次最多能显示多少张图片?有多少图片需要进行预加载,因为有可能很快也会显示在屏幕上?

  • 你的设备的屏幕大小和分辨率分别是多少?一个超高分辨率的设备(例如 Galaxy Nexus) 比起一个较低分辨率的设备(例如 Nexus S),在持有相同数量图片的时候,需要更大的缓存空间。

  • 图片的尺寸和大小,还有每张图片会占据多少内存空间。

  • 图片被访问的频率有多高?会不会有一些图片的访问频率比其它图片要高?如果有的话,你也许应该让一些图片常驻在内存当中,或者使用多个LruCache 对象来区分不同组的图片。

  • 你能维持好数量和质量之间的平衡吗?有些时候,存储多个低像素的图片,而在后台去开线程加载高像素的图片会更加的有效。

并没有一个指定的缓存大小可以满足所有的应用程序,这是由你决定的。你应该去分析程序内存的使用情况,然后制定出一个合适的解决方案。一个太小的缓存空 间,有可能造成图片频繁地被释放和重新加载,这并没有好处。而一个太大的缓存空间,则有可能还是会引起 java.lang.OutOfMemory 的异常。

下面是一个使用 LruCache 来缓存图片的例子:

[java] view plaincopy

  1. private LruCache<String, Bitmap> mMemoryCache;  

  2.   

  3. @Override  

  4. protected void onCreate(Bundle savedInstanceState) {  

  5.     // 获取到可用内存的最大值,使用内存超出这个值会引起OutOfMemory异常。  

  6.     // LruCache通过构造函数传入缓存值,以KB为单位。  

  7.     int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);  

  8.     // 使用最大可用内存值的1/8作为缓存的大小。  

  9.     int cacheSize = maxMemory / 8;  

  10.     mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {  

  11.         @Override  

  12.         protected int sizeOf(String key, Bitmap bitmap) {  

  13.             // 重写此方法来衡量每张图片的大小,默认返回图片数量。  

  14.             return bitmap.getByteCount() / 1024;  

  15.         }  

  16.     };  

  17. }  

  18.   

  19. public void addBitmapToMemoryCache(String key, Bitmap bitmap) {  

  20.     if (getBitmapFromMemCache(key) == null) {  

  21.         mMemoryCache.put(key, bitmap);  

  22.     }  

  23. }  

  24.   

  25. public Bitmap getBitmapFromMemCache(String key) {  

  26.     return mMemoryCache.get(key);  

  27. }  

在 这个例子当中,使用了系统分配给应用程序的八分之一内存来作为缓存大小。在中高配置的手机当中,这大概会有4兆(32/8)的缓存空间。一个全屏幕的 GridView 使用4张 800x480分辨率的图片来填充,则大概会占用1.5兆的空间(800*480*4)。因此,这个缓存大小可以存储2.5页的图片。
当向 ImageView 中加载一张图片时,首先会在 LruCache 的缓存中进行检查。如果找到了相应的键值,则会立刻更新ImageView ,否则开启一个后台线程来加载这张图片。

[java] view plaincopy

  1. public void loadBitmap(int resId, ImageView imageView) {  

  2.     final String imageKey = String.valueOf(resId);  

  3.     final Bitmap bitmap = getBitmapFromMemCache(imageKey);  

  4.     if (bitmap != null) {  

  5.         imageView.setImageBitmap(bitmap);  

  6.     } else {  

  7.         imageView.setImageResource(R.drawable.image_placeholder);  

  8.         BitmapWorkerTask task = new BitmapWorkerTask(imageView);  

  9.         task.execute(resId);  

  10.     }  

  11. }  

BitmapWorkerTask 还要把新加载的图片的键值对放到缓存中。

[java] view plaincopy

  1. class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {  

  2.     // 在后台加载图片。  

  3.     @Override  

  4.     protected Bitmap doInBackground(Integer... params) {  

  5.         final Bitmap bitmap = decodeSampledBitmapFromResource(  

  6.                 getResources(), params[0], 100100);  

  7.         addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);  

  8.         return bitmap;  

  9.     }  

  10. }


本文转载自:

共有 人打赏支持
娶到笨笨
粉丝 6
博文 51
码字总数 6482
作品 0
奉化
私信 提问
为什么Android官方废弃SoftRefrerence软引用和WeakReference弱引用,而拥抱LruCache?

为什么Android官方废弃SoftRefrerence软引用和WeakReference弱引用,而拥抱LruCache? 一些具有Java背景的研发者喜欢使用软引用(SoftRefrerence)和弱引用(WeakReference)来缓存Java对象和数据...

开开心心过
2018/06/09
0
0
Android内存优化之内存缓存

什么是缓存? 缓存技术原理就是把用户访问的所有对象看作一个全集,经过算法标记哪些是用户经常访问的对象,把这些对象放到一个集合里,这个集合是全集一个子集,下一次用户再访问的时候会先...

今晚打猴子
2015/08/21
0
0
安卓图片的异步请求及使用LruCache缓存和手机内存两层存储图片,避免重新加载页面带来的重新请求

看到网友的一片技术博客讲解了LruCache的使用,我把它加到了我的项目中,但是加入断点发现,列表上下滑动时,确实可以不用重新加载图片,但是重新打开这个activity或者重新启动应用,LruCach...

bluecoffee
2015/04/03
0
0
【转】Android照片墙应用实现,再多的图片也不怕崩溃

出处:http://blog.csdn.net/guolinblog/article/details/9526203 照片墙这种功能现在应该算是挺常见了,在很多应用中你都可以经常看到照片墙的身影。它的设计思路其实也非常简单,用一个Gri...

bluecoffee
2015/04/02
0
0
Android源码解析——LruCache

我认为在写涉及到数据结构或算法的实现类的源码解析博客时,不应该急于讲它的使用或马上展开对源码的解析,而是要先交待一下这个数据结构或算法的资料,了解它的设计,再从它的设计出发去讲如...

浩码农
2016/05/13
0
0

没有更多内容

加载失败,请刷新页面

加载更多

【PG内核】pg11秒级新增非空默认字段的实现方法

pg11新特性,可以瞬间向一个表中添加非空默认字段。 今天研究了一下这个特性的内核实现方式,写个博客简单记录一下。 结论奉上 pg在从硬盘或者内存获取到一条数据记录后(以下称tuple),会使...

movead
16分钟前
1
0
如何保证MongoDB的安全性?

上周写了个简短的新闻《MongoDB裸奔,2亿国人求职简历泄漏!》: 根据安全站点HackenProof的报告,由于MongoDB数据库没有采取任何安全保护措施,导致共计202,730,434份国人求职简历泄漏。 然...

Fundebug
22分钟前
1
0
KVM

目录 (1):简介及安装 1. KVM 介绍 1.0 虚拟化简史 1.1 KVM 架构 2. KVM 的功能列表 3. KVM 工具集合 4. RedHat Linux KVM 安装 4.1 在安装 RedHat Linux 时安装 KVM 4.2 在已有的 RedHat...

临江仙卜算子
37分钟前
0
0
脚本配置java开发环境

@echo off&setlocal enabledelayedexpansion cls @echo "This script is used to registe envionment variables......" @echo. @echo. @echo. set var=%~dp0 set var=%var:~,-1% @echo "regi......

默克鱼
57分钟前
1
0
c++中友元函数理解与使用

在学习c++这一块,关于友元函数和友元类,感觉还是不好理解,但是井下心来,理解,需要把我一下几点。 首先讲友元函数。 (1)友元函数: 1)C++中引入友元函数,是为在该类中提供一个对外(除...

天王盖地虎626
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部