Android工具類之圖片加載第三方封裝緩存優化
一、OOM的原因
OOM:所謂的OOM指的就是Out-of-Memory內存不足啦。Android上加載圖片OOM無非也就那么幾個。
1、Bitmap用完沒有回收,導致內存泄漏。2、手機像素越來越高,照片體積越來越大,在上傳及加載時如不進行壓縮處理,OOM是常有的事。3、機型偏舊、內存偏小。近幾年Android的發力生猛,機型配置雖然一路飆升,但是仍然有一部分人還在用著兩年前的機器。作為app的廠商又不能放棄這一部分用戶。無奈,開發時還是得根據機型做適配。
二、解決方案
首選當然還是得選擇第三方圖片加載庫,主流的加載庫無非是UniversalImageLoader、Fresco、Glide、Picasso,推薦Glide。
按照界面圖片尺寸,加載不同尺寸的圖片
LruCache 緩存工具類
要實現圖片加載最優,單單靠以上某一種方式處理肯定是不靠譜的,所以我們要使用的是三者結合來處理。是的,你沒有聽錯。
三、分析原由
1.市面上主流的圖片加載開源庫,在磁盤緩存,內存管理,圖片加載優化方面已經做了很好的處理,犯不著自己去實現一套圖片加載機制,選擇第三方開源庫也是理所當然。一般情況,直接用第三方庫加載圖片即可,幾乎不用做額外處理,當然復雜的情況就需要結合第三方庫進行優化處理了。
2.按照不同的圖片控件尺寸去加載圖片,可以減少內存開銷,節省資源,提高加載速度。例如微信朋友圈,在列表界面加載縮略小圖,點擊查看時才加載大圖。我們項目開發時,圖片上傳與存儲用的是七牛云存儲,而七牛云存儲本身提供強大的圖片處理API,可以根據請求的鏈接,獲取不同尺寸的圖片,方便開發們結合自身項目需求,實現最優圖片尺寸加載方案。七牛圖片處理API文檔地址放在文章最底下,有興趣的可以了解下。
3.今天的主角LruCache,什么是LruCache?LruCache是android提供的一個緩存工具類,其算法是最近最少使用算法。它把最近使用的對象用“強引用”存儲在LinkedHashMap中,并且把最近最少使用的對象在緩存值達到預設定值之前就從內存中移除。其在API12被引進,低版本可以用support包中的類。所以我們用LruCache來緩存加載的Bitmap,當內存低于我們設定的值后,LruCache便會自動幫我們回收用不到的資源。
四、代碼
具體原因已經分析,廢話不多說,直接上代碼
1、LruCacheUtils工具類
import android.graphics.Bitmap;
import android.util.LruCache;
/**
- Created by leo on 16/8/17.
LruCache 圖片緩存優化處理類
*/
public class LruCacheUtils extends LruCache<String, Bitmap> {
//獲取手機內存大小
private static int MAXMEMONRY = (int) (Runtime.getRuntime().maxMemory() / 1024);
private static LruCacheUtils cacheUtils;
private LruCacheUtils(int maxSize) {
super(maxSize);
}
/**
單例
*/
public static LruCacheUtils getInstance() {
if (cacheUtils == null) {
//創建對象時分配緩存,我們取內存的5分之一
cacheUtils = new LruCacheUtils(MAXMEMONRY / 5);
}
return cacheUtils;
}
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight() / 1024;
}
@Override
protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
super.entryRemoved(evicted, key, oldValue, newValue);
}
/**
- 清理緩存
*/
public void clearCache() {
if (cacheUtils.size() > 0) {
cacheUtils.evictAll();
}
}
/**
* 添加緩存圖片
*/
public synchronized void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (cacheUtils.get(key) != null) {
return;
}
if (!isEmpty(key) && bitmap != null) {
cacheUtils.put(key, bitmap);
}
}
/**
* 獲取緩存圖片
*/
public synchronized Bitmap getBitmapFromMemCache(String key) {
if (isEmpty(key)) {
return null;
}
Bitmap bm = cacheUtils.get(key);
if (bm != null && !bm.isRecycled()) {
return bm;
}
return null;
}
/**
* 移除緩存
*
* @param key
*/
public synchronized void removeImageCache(String key) {
if (isEmpty(key)) {
return;
}
Bitmap bm = cacheUtils.remove(key);
if (bm != null && !bm.isRecycled()) {
bm.recycle();
}
}
/**
* 判斷字符串是否為空
*
* @param str
* @return
*/
public boolean isEmpty(String... str) {
if (str == null) {
return true;
}
for (String s : str) {
if (s == null || s.isEmpty() || s.trim().isEmpty()) {
return true;
}
}
return false;
}
}</code></pre>
2、LruCacheUtils使用
String url = http://i2.buimg.com/567571/d208d52913b997bb.jpg?imageView2/2/w/
200;
ImageView photoView = new ImageView();
//判斷緩存中是否已經緩存過該圖片,有則直接拿Bitmap,沒有則直接調用Glide加載并緩存Bitmap
Bitmap bitmap = LruCacheUtils.getInstance().getBitmapFromMemCache(url);
if (bitmap != null) {
photoView.setImageBitmap(bitmap);
} else {
PhotoLoader.displayImageTarget(photoView, url, getTarget(photoView,
url, position));
}
3、圖片加載方法
/**
* 加載圖片 Target
*
* @param imageView
* @param target
* @param url
*/
public void displayImageTarget(final ImageView imageView, final String
url, BitmapImageViewTarget target) {
Glide.get(imageView.getContext()).with(imageView.getContext())
.load(url)
.asBitmap()//強制轉換Bitmap
.diskCacheStrategy(DiskCacheStrategy.NONE)
.into(target);
}
/**
* 獲取BitmapImageViewTarget
*/
private BitmapImageViewTarget getTarget(ImageView imageView, final String url,
final int position) {
return new BitmapImageViewTarget(imageView) {
@Override
protected void setResource(Bitmap resource) {
super.setResource(resource);
//緩存Bitmap,以便于在沒有用到時,自動回收
LruCacheUtils.getInstance().addBitmapToMemoryCache(url,
resource);
}
};
}</code></pre>
五、調試查看。
優化完成后,運行程序,在Android studio中找到Monitors一欄,進行圖片查看測試,就能清楚的看到內存變化以及釋放的過程啦。優化之前是直接使用Glide進行加載圖片,內存曾一路飆升到200M,并且很難釋放。加了縮略圖以及LruCache優化后,內存一直保持在40M-80M之間。測試結果,基本上沒有重現過OOM的情況。

PS:建議app中所有加載過的bitmap都直接扔到LruCacheUtils中進行緩存,在bitmap沒有使用時,方便系統對齊回收。調用上面代碼前,請記得集成Glide開源庫哦。如果你使用以上方法進行圖片加載優化,還是會出現OOM的話,那就說明......你可能要換手機了……
來自:http://www.jianshu.com/p/d8890404d87b