2013-05-22 51 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); 
    } 
}