這個問題曾經讓我覺得很煩惱,後來終於得到了解決,
那麼現在就讓我和大家一起分享一下吧。
這篇博文要講的圖片緩存機制,我接觸到的有兩鍾,一種是軟引用,另一種是內存緩存技術。
先來看下兩者的使用方式,再來作比較。
除了加載圖片時要用到緩存處理,還有一個比較重要的步驟要做,就是要先壓縮圖片。
1、壓縮圖片
至於要壓縮到什麼狀態就要看自己當時的處境了,壓縮圖片的時候既要達到一個小的值,又不能讓其模糊
,更不能拉伸圖片。
-
/**
-
* 加載內存卡圖片
-
*/
-
BitmapFactory.Options options = new BitmapFactory.Options();
-
options.inJustDecodeBounds = true; //
設置了此屬性一定要記得將值設置爲false
-
Bitmap bitmap = null;
-
bitmap = BitmapFactory.decodeFile(url, options);
-
int be = (int) ((options.outHeight > options.outWidth ? options.outHeight / 150
-
: options.outWidth / 200));
-
if (be <= 0) //
判斷200是否超過原始圖片高度
-
be = 1; // 如果超過,則不進行縮放
-
options.inSampleSize = be;
-
options.inPreferredConfig = Bitmap.Config.ARGB_4444;
-
options.inPurgeable = true;
-
options.inInputShareable = true;
-
options.inJustDecodeBounds = false;
-
try {
-
bitmap = BitmapFactory.decodeFile(url, options);
-
} catch (OutOfMemoryError e) {
-
System.gc();
-
Log.e(TAG, "OutOfMemoryError");
- }
2、軟引用:
只要有足夠的內存,就一直保持對象,直到發現內存吃緊且沒有Strong Ref時纔回收對象。
我們可以這樣定義:map裏面的鍵是用來放圖片地址的,既可以是網絡上的圖片地址,也可以SDcard上的圖片地址,
map裏面的值裏面放的是持有軟引用的Bitmap,當然如果你要放Drawable,那也是可以的。
- private Map<String, SoftReference<Bitmap>> imageMap
- = new HashMap<String, SoftReference<Bitmap>>();
步驟:(1)先通過URL查看緩存中是否有圖片,如果有,則直接去緩存中取得。
如果沒有,就開線程重新去網上下載。
(2)下載完了之後,就把圖片放在緩存裏面,方便下次可以直接從緩存中取得。
-
public Bitmap loadBitmap(final String imageUrl,final ImageCallBack
imageCallBack) {
-
SoftReference<Bitmap> reference = imageMap.get(imageUrl);
-
if(reference != null) {
-
if(reference.get() != null) {
-
return reference.get();
-
}
-
}
-
final Handler handler = new Handler() {
-
public void handleMessage(final android.os.Message
msg) {
-
//加入到緩存中
-
Bitmap bitmap = (Bitmap)msg.obj;
-
imageMap.put(imageUrl, new SoftReference<Bitmap>(bitmap));
-
if(imageCallBack != null) {
-
imageCallBack.getBitmap(bitmap);
-
}
-
}
-
};
-
new Thread(){
-
public void run() {
-
Message message = handler.obtainMessage();
-
message.obj = downloadBitmap(imageUrl);
-
handler.sendMessage(message);
-
}
-
}.start();
-
return null ;
-
}
-
-
// 從網上下載圖片
-
private Bitmap downloadBitmap (String imageUrl) {
-
Bitmap bitmap = null;
-
try {
-
bitmap = BitmapFactory.decodeStream(new URL(imageUrl).openStream());
-
return bitmap ;
-
} catch (Exception e) {
-
e.printStackTrace();
-
return null;
-
}
- }
-
public interface ImageCallBack{
-
void getBitmap(Bitmap bitmap);
- }
2、內存緩存技術
另外一種圖片緩存的方式就是內存緩存技術。在Android中,有一個叫做LruCache類專門用來做圖片緩存處理的。
它有一個特點,當緩存的圖片達到了預先設定的值的時候,那麼近期使用次數最少的圖片就會被回收掉。
步驟:(1)要先設置緩存圖片的內存大小,我這裏設置爲手機內存的1/8,
手機內存的獲取方式:int MAXMEMONRY = (int) (Runtime.getRuntime() .maxMemory() / 1024);
(2)LruCache裏面的鍵值對分別是URL和對應的圖片
(3)重寫了一個叫做sizeOf的方法,返回的是圖片數量。
-
private LruCache<String, Bitmap> mMemoryCache;
-
private LruCacheUtils() {
-
if (mMemoryCache == null)
-
mMemoryCache = new LruCache<String, Bitmap>(
-
MAXMEMONRY / 8) {
-
@Override
-
protected int sizeOf(String key, Bitmap
bitmap) {
-
// 重寫此方法來衡量每張圖片的大小,默認返回圖片數量。
-
return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
-
}
-
-
@Override
-
protected void entryRemoved(boolean evicted, String key,
-
Bitmap oldValue, Bitmap newValue) {
-
Log.v("tag", "hard
cache is full , push to soft cache");
-
-
}
-
};
- }
移除和清除緩存是必須要做的事,因爲圖片緩存處理不當就會報內存溢出,所以一定要引起注意。
-
public void clearCache() {
-
if (mMemoryCache != null) {
-
if (mMemoryCache.size() > 0) {
-
Log.d("CacheUtils",
-
"mMemoryCache.size() " + mMemoryCache.size());
-
mMemoryCache.evictAll();
-
Log.d("CacheUtils", "mMemoryCache.size()" + mMemoryCache.size());
-
}
-
mMemoryCache = null;
-
}
-
}
-
-
public synchronized void addBitmapToMemoryCache(String key, Bitmap
bitmap) {
-
if (mMemoryCache.get(key) == null) {
-
if (key != null && bitmap != null)
-
mMemoryCache.put(key, bitmap);
-
} else
-
Log.w(TAG, "the
res is aready exits");
-
}
-
-
public synchronized Bitmap getBitmapFromMemCache(String key) {
-
Bitmap bm = mMemoryCache.get(key);
-
if (key != null) {
-
return bm;
-
}
-
return null;
-
}
-
-
/**
-
* 移除緩存
-
*
-
* @param key
-
*/
-
public synchronized void removeImageCache(String key) {
-
if (key != null) {
-
if (mMemoryCache != null) {
-
Bitmap bm = mMemoryCache.remove(key);
-
if (bm != null)
-
bm.recycle();
-
}
-
}
- }
4、兩者的比較
說到這裏,我覺得有必要來進行一下比較了。
網上有很多人使用軟引用加載圖片的多 ,但是現在已經不再推薦使用這種方式了,
(1)因爲從 Android 2.3 (API Level 9)開始,垃圾回收器會更傾向於回收持有軟引用或弱引用的對象,
這讓軟引用和弱引用變得不再可靠。
(2)另外,Android 3.0 (API Level 11)中,圖片的數據會存儲在本地的內存當中,
因而無法用一種可預見的方式將其釋放,這就有潛在的風險造成應用程序的內存溢出並崩潰,
所以我這裏用得是LruCache來緩存圖片,當存儲Image的大小大於LruCache設定的值,系統自動釋放內存,
這個類是3.1版本中提供的,如果你是在更早的Android版本中開發,則需要導入android-support-v4的jar包。