【问题标题】:Android: Image cache strategy and memory cache sizeAndroid:图像缓存策略和内存缓存大小
【发布时间】:2011-03-06 08:22:54
【问题描述】:

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

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

我的类与droidfu project中使用的类非常相似

我下载的图像被放入哈希图中,位图对象是 包裹在 SoftRererence 对象中。还保存了每个图像 永久保存到磁盘。 如果请求的图像未在 Hashmap<String,SoftReference<Bitmap>>会在磁盘上搜索, 读取,然后推回哈希图中。否则图像会 从网络下载的。 由于我将图像存储到物理设备内存中,因此我添加了一项检查以保留设备空间并保持在 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 已经足够了”

【问题讨论】:

标签: android memory caching bitmap


【解决方案1】:

别这样! SoftReference 已经足够了! 实际上,SoftReference 旨在完全满足您的需求。 有时 SoftReference 不能满足您的需要。然后你只需摆脱 SoftReference 并编写自己的内存管理逻辑。但就您使用 SoftReference 而言,您不必担心内存消耗,SoftReference 会为您解决。

【讨论】:

  • Android 以一种不适合这种缓存的方式实现软引用。有关详细信息,请参阅此错误报告:code.google.com/p/android/issues/…。图像将在只能通过 SoftReference 访问的那一刻从内存中删除。 Google 团队建议使用 LRU 缓存。这里的问题是确定缓存的最大大小。
  • @Janusz,这是真的。但是由于没有每个初学者都可以采用和重用的 LRU 缓存实现,因此他们必须从 SoftReference 开始。它并不完美(我知道你在谈论的问题),但它已经足够开始了。
  • 我认为这还不够好。随着速度的加快,内存在软引用无用并引起很多混乱时被释放。使用它们绝对没有任何好处。
  • @Janusz 是的,你可能是对的。然后我们应该想出一个非常基本的方法,我们可以推荐给初学者。
  • 谁在为“初学者”寻求解决方案?我认为问题是关于正确的解决方案。如果系统仅因为图像未被缓存以外的其他人引用而将其删除,则这不是正确的解决方案。
【解决方案2】:

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

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

顺便说一下,关于软引用,在 Android 中,软引用不能按预期工作。存在平台问题,即过早收集软引用,即使有大量可用内存也是如此。

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

【讨论】:

    【解决方案3】:

    我一直在为我的缩放位图研究不同的缓存机制,包括内存和磁盘缓存示例。这些示例根据我的需要进行了复杂化,因此我最终使用 LruCache 制作了自己的位图内存缓存。 您可以查看工作代码示例here 或使用以下代码:

    内存缓存:

    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;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2012-09-20
      • 2010-10-06
      • 1970-01-01
      • 2011-06-10
      • 2019-05-05
      • 1970-01-01
      • 2012-09-05
      • 2020-08-03
      • 2011-11-12
      相关资源
      最近更新 更多