2019独角兽企业重金招聘Python工程师标准>>>

使用图片缓存技术

在你应用程序的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]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private LruCache<String, Bitmap> mMemoryCache;  
@Override
protected void onCreate(Bundle savedInstanceState) { 
     // 获取到可用内存的最大值,使用内存超出这个值会引起OutOfMemory异常。 
     // LruCache通过构造函数传入缓存值,以KB为单位。 
     int maxMemory = ( int ) (Runtime.getRuntime().maxMemory() / 1024 ); 
     // 使用最大可用内存值的1/8作为缓存的大小。 
     int cacheSize = maxMemory /  8
     mMemoryCache =  new LruCache<String, Bitmap>(cacheSize) { 
         @Override
         protected int sizeOf(String key, Bitmap bitmap) { 
             // 重写此方法来衡量每张图片的大小,默认返回图片数量。 
             return bitmap.getByteCount() /  1024
        
     }; 
    
public void addBitmapToMemoryCache(String key, Bitmap bitmap) { 
     if (getBitmapFromMemCache(key) ==  null ) { 
         mMemoryCache.put(key, bitmap); 
    
    
public Bitmap getBitmapFromMemCache(String key) { 
     return mMemoryCache.get(key); 
}

在这个例子当中,使用了系统分配给应用程序的八分之一内存来作为缓存大小。在中高配置的手机当中,这大概会有4兆(32/8)的缓存空间。一个全屏幕的 GridView 使用4张 800x480分辨率的图片来填充,则大概会占用1.5兆的空间(800*480*4)。因此,这个缓存大小可以存储2.5页的图片。

当向 ImageView 中加载一张图片时,首先会在 LruCache 的缓存中进行检查。如果找到了相应的键值,则会立刻更新ImageView ,否则开启一个后台线程来加载这张图片。

[java]

1
2
3
4
5
6
7
8
9
10
11
public void loadBitmap( int resId, ImageView imageView) { 
     final String imageKey = String.valueOf(resId); 
     final Bitmap bitmap = getBitmapFromMemCache(imageKey); 
     if (bitmap !=  null ) { 
         imageView.setImageBitmap(bitmap); 
     else
         imageView.setImageResource(R.drawable.image_placeholder); 
         BitmapWorkerTask task =  new BitmapWorkerTask(imageView); 
         task.execute(resId); 
    
}

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

[java]

1
2
3
4
5
6
7
8
9
10
class BitmapWorkerTask  extends AsyncTask<Integer, Void, Bitmap> { 
     // 在后台加载图片。 
     @Override
     protected Bitmap doInBackground(Integer... params) { 
         final Bitmap bitmap = decodeSampledBitmapFromResource( 
                 getResources(), params[ 0 ],  100 100 ); 
         addBitmapToMemoryCache(String.valueOf(params[ 0 ]), bitmap); 
         return bitmap; 
    
}

转载于:https://my.oschina.net/u/1429620/blog/191156

Android使用 LruCache 缓存图片相关推荐

  1. android lrucache,Android——使用LruCache缓存图片

    为什么要缓存图片: (1)根据具体设备的不同Android系统为每个应用分配了固定内存空间供应用使用: (2)图片是一种很占内存的资源文件,如果界面中加载一张图片还好说,如果要加载大量的图片就会超过系 ...

  2. LruCache缓存图片+清除本地缓存

    /**  *  * 本应用数据清除管理器  */ public class DataClearManager { /**      * 获取本应用缓存大小      * @param context ...

  3. android 自动清理缓存图片吗,Android中Glide获取缓存大小并清除缓存图片

    清除Glide缓存 Glide自带清除缓存的功能,分别对应Glide.get(context).clearDiskCache();(清除磁盘缓存)与Glide.get(context).clearMe ...

  4. android xutils框架缓存图片,xUtils框架的使用

    xUtils简介 xUtils 包含了很多实用的android工具,xUtils 源于Afinal框架,对Afinal进行了大量重构,使得xUtils支持大文件上传,更全面的http请求协议支持,拥有 ...

  5. android读写缓存文件路径,Android app-cache-Path的 缓存图片、缓存文件的路径包名路径 和外路径比较...

    代码对应的路径: //判断手机是否挂在sd卡 String externalStorageState= Environment.getExternalStorageState(); File down ...

  6. android app 清理缓存图片,支付宝APP怎么清理缓存 支付宝安卓版缓存清理方法

    当今社会支付方式已经越来越便捷化了,普通的现金支付方式已经逐渐被人们放弃,现在大部分朋友们都会使用支付宝APP进行手机移动支付.相信大家都知道,这款软件除了支付功能以外,还有许多其他功能,而这些功能往 ...

  7. android picasso 三级缓存,Android中图片的三级缓存浅析

    图片的三级缓存机制一般是指应用加载图片的时候,分别去访问内存,文件和网络而获取图片数据的一种行为.以下内容只是简单的介绍了三级缓存的思想和大致流程,还有很多细节未进行处理,如果想深入研究可以在Gith ...

  8. android 用LruCache读取大图片并缓存(转)

    图片预取缓存策略是内存缓存(硬引用LruCache.软引用SoftReference<Bitmap>).外部文件缓存(context.getCachedDir()),缓存中取不到的情况下再 ...

  9. Android LruCache 压缩图片 有效避免程序OOM

    压缩加载大图片 我们在编写Android程序的时候经常要用到许多图片,不同图片总是会有不同的形状.不同的大小,但在大多数情况下,这些图片都会大于我们程序所需要的大小.比如说系统图片库里展示的图片大都是 ...

最新文章

  1. 基于PU-Learning的恶意URL检测——半监督学习的思路来进行正例和无标记样本学习...
  2. 8大策略让你对抗机器学习数据集里的不均衡数据
  3. pcl_openmap_OpenMap教程5 – 3层GIS应用程序
  4. PAL/NTSC/SECAM,这是全球现行的三种模拟技术彩色电视的制式
  5. 【java】java 模拟 实现一个 ThreadPoolExecutor
  6. 微软以白金会员加入 OpenChain 开源组织
  7. 函数 的 重载 和 函数 模版
  8. 学前教育与计算机,计算机与幼儿教育
  9. Java知多少(87)选择框和单选按钮
  10. 2022.02.10
  11. python编程100例海绵宝宝-Python_Turtle库画一只派大星
  12. 100行代码实现HarmonyOS“画图”应用,eTS开发走起
  13. Clion安装教程(Linux)
  14. MySQL installer直接解决安装(包括不想安在c盘也OK)、更新、卸载问题
  15. 第二证券|钠电池三种技术路线谁更将率先取代锂电池?
  16. c语言编程编写计算器图形,c语言编写的图形计算器.DOC
  17. 省时省力,高速收费站无线组网解决方案
  18. Composer开启多线程组件改变composer缓慢问题
  19. (转)刹车离合同时踩非常危险
  20. python爬取微信读书APP的书单

热门文章

  1. Mycat简单实现读写分离与分库分表
  2. Alternating Least Squares(ASL) for Implicit Feedback Datasets的数学推导以及用Python实现
  3. 《Visual C++数字图像模式识别技术详解(第2版)》一3.4 形状特征
  4. [android] 切换按钮-自定义控件-拖动效果
  5. 不聋不哑,不做当家之解
  6. 物联网的兴起与二维码的前景
  7. Windows XP SP2疑难速解50问
  8. oracle和MySQL的日期函数_mysql与oracle的日期/时间函数小结
  9. 【python】简单实现一个模板引擎
  10. javascript之window对象