本站已关停,现有内容仅作科研等非赢利用途使用。特此声明。
查看: 10865|回复: 2
打印 上一主题 下一主题

[Android分享] Memory cache

[复制链接]
跳转到指定楼层
1#
发表于 2013-3-27 15:44:29 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

在UI界面加载一个Bitmap是很简单的,然而当你加载图片集就变的不容易了。像ListView、GridView、ViewPager等显示一系列的图片,尤其在滑动时的处理。

一般情况下,你都要尽可能的减少内存的使用。但是有时候你要保证UI的流畅和加载速度,就要使用缓存的技术了。

接下来就用缓存Bitmap的例子来介绍如何使用缓存,本章只介绍Memory cache。

使用内存缓存(Memory cache)

Memory cache可以快速获取Bitmap,但是需要使用APP的宝贵的内存。Android API 中为我们提供了一个很合适的类LruCache,它使用强引用(strong reference)的LinkedHashMap来保存最近使用的一些对象。当缓存大小超出了限定的大小时,它会将最近最少使用的对象剔除。

注意:在过去,实现Memory cache的一个很流行的方法就是使用软引用( SoftReference)或者弱引用( WeakReference )来缓存一个对象,然而这种做法是不推荐使用的。自Android 2.3开始,GC会更加积极地回收软引用和弱引用,致使这种Memory cache实现方式失效。除此之外,在Android3.0之前,Bitmap对象不是分配在App的内存中,而是分配在本机的内存(native memory)中。达到预定条件后也不会释放这些对象,从而可能导致程序超过内存限制并崩溃。

在使用 LruCache 的时候,需要考虑如下一些因素来分配一个合适的缓存大小:
1.在App中还有多少内存可用?
2.同时在屏幕上显示多少图片?要先缓存多少图片用来显示到即将看到的屏幕上?
3.设备的屏幕尺寸和屏幕密度是多少?超高的屏幕密度(xhdpi 例如 Galaxy Nexus)
设备显示同样的图片要比低屏幕密度(hdpi 例如 Nexus S)设备需要更多的内存。
4.Bitmap的尺寸和配置(configuration)决定了每个图片需要占用多少内存。
5.图片访问频率如何?一些图片的访问频率要比其他图片高很多?如果是这样的话,您可能需要把这些经常访问的图片放到内存中。或者建立多个LruCache.
6.在质量和数量上如何平衡?有些时候保存大量的低质量的图片是更加有用的,当需要的情况下使用后台线程来载入一个高质量版本的图片。

对于不同的APP,没有标准的分配缓存大小的方案。需要分析您的使用情况并在指定自己的缓存策略。使用太小的缓存并不能起到应有的效果,而使用太大的缓存会消耗更多
的内存从而有可能导致 java.lang.OutOfMemory 异常或者留下很少的内存供您的程序其他功能使用。


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

   final int cacheSize = maxMemory / 8;

    LruCache<String,Bitmap> mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
        @Override
        protected int sizeOf(String key, Bitmap bitmap) {
            // The cache size will be measured in kilobytes rather than
            // number of items.
            return bitmap.getByteCount() / 1024;
        }
    };

上面代码片段给LruCache分配了整个App的1/8的内存。 也就是说在一个 normal/hdpi 的设备上至少分配了4MB(32/8)的缓存空间。在一个分辨率为 800×480的设备中,满屏的GridView全部填充上图片将会使用差不多1.5MB(800*480*4 bytes)
的内存,所以这样差不多在内存中缓存了2.5页的图片。


以上就LruCache 缓存的介绍,当然我们还可以使用LinkedHashMap来实现。其实LruCache就是基于LinkedHashMap实现的。

我们现在可以解决我之前分享的文章: [Android分享]多线程提升性能和体验 中提及到图片缓存的问题了:

当下在图片成功后,调用以下方法,将Bitmap加入到缓存。
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
    if (getBitmapFromMemCache(key) == null) {
        mMemoryCache.put(key, bitmap);
    }
}

当要显示图片时,要调用以下方法判断是否存在缓存中,如果不存在再去下载。
public Bitmap getBitmapFromMemCache(String key) {
    return mMemoryCache.get(key);
}



OK,缓存不是只有Memory cache,还有磁盘缓存(Disk cache)。之后会介绍Disk cache的实现。

ChinaGDG.com
回复

使用道具 举报

2#
发表于 2013-3-31 01:23:06 | 只看该作者
用这套机制已经有一段时间了,但是后台统计显示还是经常出现OutOfMemeryException,不知兄台有没有什么好的建议
ChinaGDG.com
回复 支持 反对

使用道具 举报

3#
 楼主| 发表于 2013-4-1 09:54:40 | 只看该作者
wader 发表于 2013-3-31 01:23
用这套机制已经有一段时间了,但是后台统计显示还是经常出现OutOfMemeryException,不知兄台有没有什么好的 ...


具体情况能不能说的再清楚一点?

使用Memory cache 时应该注意及时释放
(1).在不再使用时手动释放掉
(2).在内存很低的情况下,要及时释放掉。
ChinaGDG.com
回复 支持 反对

使用道具 举报

*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表