Android:图像缓存策略和内存缓存大小

发布于 2024-09-06 03:10:50 字数 2253 浏览 6 评论 0 原文

我正在实现一个图像缓存系统来缓存下载的图像。

我的策略是基于两级缓存: 内存级和磁盘级。

我的类与 droidfu 项目

我下载的图像被放入哈希图中,位图对象是 包装在 SoftRererence 对象内。每张图像也会被保存 永久到磁盘。 如果在搜索中找不到所请求的图像 Hashmap> 将会在磁盘上进行搜索, 读取,然后推回到哈希图中。否则图像将是 从网络下载的。 由于我将图像存储到物理设备内存中,因此我添加了一项检查以保留设备空间并保持在 1M 的占用空间以下:

private void checkCacheUsage() {

        long size = 0;
        final File[] fileList = new File(mCacheDirPath).listFiles();
        Arrays.sort(fileList, new Comparator<File>() {
            public int compare(File f1, File f2) {
                return Long.valueOf(f2.lastModified()).compareTo(
                        f1.lastModified());
            }
        });
        for (File file : fileList) {
            size += file.length();
            if (size > MAX_DISK_CACHE_SIZE) {
                file.delete();
                Log.d(ImageCache.class.getSimpleName(),
                        "checkCacheUsage: Size exceeded  " + size + "("
                                + MAX_DISK_CACHE_SIZE + ") wiping older file {"+file.toString()+"}");
            }
        }

    }

此方法在磁盘写入后的某个时间被调用:

Random r = new Random();
        int ra = r.nextInt(10);

        if (ra % 2 == 0){
            checkCacheUsage();
        }

我想添加的是相同的检查 HashMap 大小以防止其增长太多。像这样:

private synchronized void checkMemoryCacheUsage(){

            long size = 0;

            for (SoftReference<Bitmap> a : cache.values()) {

                final Bitmap b = a.get();

                if (b != null && ! b.isRecycled()){
                    size += b.getRowBytes() * b.getHeight();
                }

                if (size > MAX_MEMORY_SIZE){
                  //Remove some elements from the cache
                }

            }

            Log.d(ImageCache.class.getSimpleName(),
                    "checkMemoryCacheUsage: " + size + " in memory");

    }

我的问题是: 正确的 MAX_MEMORY_SIZE 值是多少? 另外,这是一个好方法吗? 一个好的答案也可能是:“不要这样做!SoftReference 已经足够了”

I'm implementing an image cache system for caching downloaded image.

My strategy is based upon two-level cache:
Memory-level and disk-level.

My class is very similar to the class used in the droidfu project

My downloaded images are put into an hashmap and the Bitmap objet is
wrapped inside a SoftRererence object. Also every image is saved
permanently to the disk.
If a requested image is not found into the
Hashmap<String,SoftReference<Bitmap>> it will be searched on the disk,
readed, and then pushed back into the hashmap. Otherwise the image will be
downloaded from the network.
Since I store the images into the phisical device momery, I have added a check for preserve the device space and stay under a 1M of occupied space:

private void checkCacheUsage() {

        long size = 0;
        final File[] fileList = new File(mCacheDirPath).listFiles();
        Arrays.sort(fileList, new Comparator<File>() {
            public int compare(File f1, File f2) {
                return Long.valueOf(f2.lastModified()).compareTo(
                        f1.lastModified());
            }
        });
        for (File file : fileList) {
            size += file.length();
            if (size > MAX_DISK_CACHE_SIZE) {
                file.delete();
                Log.d(ImageCache.class.getSimpleName(),
                        "checkCacheUsage: Size exceeded  " + size + "("
                                + MAX_DISK_CACHE_SIZE + ") wiping older file {"+file.toString()+"}");
            }
        }

    }

This method is called sometime afte a disk writing:

Random r = new Random();
        int ra = r.nextInt(10);

        if (ra % 2 == 0){
            checkCacheUsage();
        }

What I'd like to add is the same check on the HashMap size to prevent it will grow too much. Something like this:

private synchronized void checkMemoryCacheUsage(){

            long size = 0;

            for (SoftReference<Bitmap> a : cache.values()) {

                final Bitmap b = a.get();

                if (b != null && ! b.isRecycled()){
                    size += b.getRowBytes() * b.getHeight();
                }

                if (size > MAX_MEMORY_SIZE){
                  //Remove some elements from the cache
                }

            }

            Log.d(ImageCache.class.getSimpleName(),
                    "checkMemoryCacheUsage: " + size + " in memory");

    }

My question is:
What could be a right MAX_MEMORY_SIZE value?
Also, Is it a good approach?
A good answer also could be: "Don't do it! SoftReference is already enough"

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

动次打次papapa 2024-09-13 03:10:50

不要这样做! SoftReference 已经足够了!
实际上,SoftReference 的设计正是为了满足您的需求。
有时 SoftReference 不能满足您的需要。然后你只需摆脱 SoftReference 并编写自己的内存管理逻辑即可。但只要您使用 SoftReference,您就不应该担心内存消耗,SoftReference 会为您做到这一点。

Don't do it! SoftReference is already enough!
Actually SoftReference is designed to do exactly what you need.
Sometimes SoftReference doesn't do what you need. Then you just get rid of SoftReference and write your own memory management logic. But as far as you use SoftReference you should not be worried about memory consumption, SoftReference does it for you.

愿得七秒忆 2024-09-13 03:10:50

我将三分之一的堆用于图像缓存。

int memoryInMB = activityManager.getMemoryClass();
long totalAppHeap = memoryInMB * 1024 * 1024;
int runtimeCacheLimit =  (int)totalAppHeap/3;

顺便说一句,关于软引用,在 Android 中软引用并不像你期望的那样工作。存在一个平台问题,即即使有足够的可用内存,软引用也会过早收集。

检查http://code-gotcha.blogspot.com/2011/09/softreference。 html

I am using one-third of the heap for Image cache.

int memoryInMB = activityManager.getMemoryClass();
long totalAppHeap = memoryInMB * 1024 * 1024;
int runtimeCacheLimit =  (int)totalAppHeap/3;

By the way, about soft reference, in Android Soft references do not work as you expect. There is a platform issue that soft references are collected too early, even when there is plenty of memory free.

Check http://code-gotcha.blogspot.com/2011/09/softreference.html

香橙ぽ 2024-09-13 03:10:50

我一直在研究缩放位图的不同缓存机制,包括内存和磁盘缓存示例。这些示例对于我的需求来说很复杂,所以我最终使用 LruCache 制作了自己的位图内存缓存。
您可以查看工作代码示例 此处 或使用此代码:

内存缓存:

public class Cache {
    private static LruCache<Integer, Bitmap> bitmaps = new BitmapLruCache();

    public static Bitmap get(int drawableId){
        Bitmap bitmap = bitmaps.get(drawableId);
        if(bitmap != null){
            return bitmap;  
        } else {
            bitmap = SpriteUtil.createScaledBitmap(drawableId);
            bitmaps.put(drawableId, bitmap);
            return bitmap;
        }
    }
}

BitmapLruCache:

public class BitmapLruCache extends LruCache<Integer, Bitmap> {
    private final static int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
    private final static int cacheSize = maxMemory / 2;

    public BitmapLruCache() {
        super(cacheSize);
    }

    @Override
    protected int sizeOf(Integer key, Bitmap bitmap) {
        // The cache size will be measured in kilobytes rather than number of items.
        return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
    }
}

I've been looking into different caching mechanisms for my scaled bitmaps, both memory and disk cache examples. The examples where to complex for my needs, so I ended up making my own bitmap memory cache using LruCache.
You can look at a working code-example here or use this code:

Memory Cache:

public class Cache {
    private static LruCache<Integer, Bitmap> bitmaps = new BitmapLruCache();

    public static Bitmap get(int drawableId){
        Bitmap bitmap = bitmaps.get(drawableId);
        if(bitmap != null){
            return bitmap;  
        } else {
            bitmap = SpriteUtil.createScaledBitmap(drawableId);
            bitmaps.put(drawableId, bitmap);
            return bitmap;
        }
    }
}

BitmapLruCache:

public class BitmapLruCache extends LruCache<Integer, Bitmap> {
    private final static int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
    private final static int cacheSize = maxMemory / 2;

    public BitmapLruCache() {
        super(cacheSize);
    }

    @Override
    protected int sizeOf(Integer key, Bitmap bitmap) {
        // The cache size will be measured in kilobytes rather than number of items.
        return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文