2013-05-22 29 views

回答

48
import android.graphics.Bitmap; 
import android.support.v4.util.LruCache; 

public class BitmapLruCache extends LruCache<String, Bitmap> implements ImageCache { 
    public static int getDefaultLruCacheSize() { 
     final int maxMemory = (int) (Runtime.getRuntime().maxMemory()/1024); 
     final int cacheSize = maxMemory/8; 

     return cacheSize; 
    } 

    public BitmapLruCache() { 
     this(getDefaultLruCacheSize()); 
    } 

    public BitmapLruCache(int sizeInKiloBytes) { 
     super(sizeInKiloBytes); 
    } 

    @Override 
    protected int sizeOf(String key, Bitmap value) { 
     return value.getRowBytes() * value.getHeight()/1024; 
    } 

    @Override 
    public Bitmap getBitmap(String url) { 
     return get(url); 
    } 

    @Override 
    public void putBitmap(String url, Bitmap bitmap) { 
     put(url, bitmap); 
    } 
} 
+0

非常感谢,顺便说一句,你如何确定缓存的大小合适?他谈到它的屏幕尺寸功能似乎合乎逻辑,但我怎样才能使它更精确? – urSus

+0

@Vlasto Benny Lava,我不确定,但是像'N * screen_width * screen_height'和'N〜10'这样的东西对我来说似乎是合乎逻辑的。 –

+0

,因为现在发生的事很好,但是如果图像离开屏幕并返回,图像再次加载,所以我认为它被踢出了内存缓存?任何想法可能是什么? – urSus

1

我建议使用Singleton位图缓存,这样这个缓存将在您的应用程序的整个生命周期中可用。

public class BitmapCache implements ImageCache { 
    private LruCache<String, Bitmap> mMemoryCache; 

    private static BitmapCache mInstance; 

    private BitmapCache(Context ctx) { 
     final int memClass = ((ActivityManager) ctx 
       .getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass(); 
     // Use 1/16th of the available memory for this memory cache. 
     final int cacheSize = 1024 * 1024 * memClass/16; 
     mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { 
      @Override 
      protected int sizeOf(String key, Bitmap value) { 
       return value.getRowBytes() * value.getHeight(); 
      } 
     }; 
    } 

    public static BitmapCache getInstance(Context ctx) { 
     if (mInstance == null) { 
      mInstance = new BitmapCache(ctx); 
     } 
     return mInstance; 
    } 

    @Override 
    public Bitmap getBitmap(String url) { 
     return mMemoryCache.get(url); 
    } 

    @Override 
    public void putBitmap(String url, Bitmap bitmap) { 
     mMemoryCache.put(url, bitmap); 
    } 
} 
5

这里是使用基于LRU缓存,排球磁盘的一个实例。它基于使用Jake Wharton维护的AOSP DiskLruCache版本。 http://blogs.captechconsulting.com/blog/raymond-robinson/google-io-2013-volley-image-cache-tutorial

编辑:我已更新项目以包含内存LRU缓存作为默认实现,因为这是推荐的方法。 Volley在其自己的L2缓存中隐式地处理基于磁盘的缓存。图像缓存就是L1缓存。我更新了原文,并在此处添加了更多细节:http://www.thekeyconsultant.com/2013/06/update-volley-image-cache.html

+1

在你的库中,你似乎在使用url.hashCode()来生成磁盘缓存所需的密钥。这真的很安全吗? hashCodes不是唯一的,所以你不会冒险得到URL的虚假缓存命中,它会随机解析为相同的哈希码?我见过其他人使用MD5来降低碰撞风险,有些甚至提供他们自己的MD5实现来避免Android非线程安全的MessageDigest类。有关这个(潜在)问题的任何建议? –

+1

你是对的,这只是适合演示,并在大多数时间工作。我正在测试UUID.fromString()的速度作为一种可行的选择。 – rdrobinson3

0

这是进来新的API来处理OOM

public class BitmapMemCache extends LruCache<string, Bitmap> implements ImageCache { 

    public BitmapMemCache() { 
     this((int) (Runtime.getRuntime().maxMemory()/1024)/8); 
    } 

    public BitmapMemCache(int sizeInKiloBytes) { 
     super(sizeInKiloBytes); 
    } 

    @Override 
    protected int sizeOf(String key, Bitmap bitmap) { 
     int size = bitmap.getByteCount()/1024; 
     return size; 
    } 

    public boolean contains(String key) { 
     return get(key) != null; 
    } 

    public Bitmap getBitmap(String key) { 
     Bitmap bitmap = get(key); 
     return bitmap; 
    } 

    public void putBitmap(String url, Bitmap bitmap) { 
     put(url, bitmap); 
    } 
}