代码之家  ›  专栏  ›  技术社区  ›  Francesco Laurita

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

  •  11
  • Francesco Laurita  · 技术社区  · 15 年前

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

    内存级别和磁盘级别。

    droidfu project

    包裹在软引用对象中。此外,还保存了每个图像 永久保存到磁盘。 如果在中找不到请求的映像 Hashmap<String,SoftReference<Bitmap>> 会在磁盘上搜索, 从网络下载。 由于我将图像存储到物理设备内存中,因此我添加了一个检查,以保留设备空间并保持在1米的占用空间以下:

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

    另外,这是一个好方法吗? 一个好的答案也可以是:“不要这样做!“软引用已经足够了”

    3 回复  |  直到 8 年前
        1
  •  8
  •   Fedor    14 年前

    别这样!软引用已经足够了! 实际上,SoftReference的设计正是为了满足您的需要。

        2
  •  1
  •   Mazed    13 年前

    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
  •  0
  •   Jan-Terje Sørensen    12 年前

    我一直在研究缩放位图的不同缓存机制,包括内存和磁盘缓存示例。这里的例子很复杂,以满足我的需要,所以我结束了我自己的位图内存缓存使用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;
            }
        }
    }
    

    位图缓存:

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