最近作了個資訊類的app項目,涉及到大量的圖片加載,因公司項目框架已經集成了Glide用於加載圖片,理所固然就直接用了Glide來加載app中的圖片。本來覺得用了Glide第三方框架就能夠高枕無憂了,然並卵,一發包測試,測試反饋部分圖片沒法加載,各類OOM。然而本身測試卻沒有任何問題,此刻個人心裏是崩潰的。一問細節,測試機型版本4.0,RAM1GB。開發調試時,機型的配置是市面上主流及較高的配置,因此一點問題都察覺不到。沒有辦法,誰讓合同上籤的最低兼容版本是4.0呢?只能作適配了。android
OOM:所謂的OOM指的就是Out-of-Memory內存不足啦。Android上加載圖片OOM無非也就那麼幾個。git
一、Bitmap用完沒有回收,致使內存泄漏。
二、手機像素愈來愈高,照片體積愈來愈大,在上傳及加載時如不進行壓縮處理,OOM是常有的事。
三、機型偏舊、內存偏小。近幾年Android的發力生猛,機型配置雖然一路飆升,可是仍然有一部分人還在用着兩年前的機器。做爲app的廠商又不能放棄這一部分用戶。無奈,開發時仍是得根據機型作適配。github
要實現圖片加載最優,單單靠以上某一種方式處理確定是不靠譜的,因此咱們要使用的是三者結合來處理。是的,你沒有聽錯。算法
1.市面上主流的圖片加載開源庫,在磁盤緩存,內存管理,圖片加載優化方面已經作了很好的處理,犯不着本身去實現一套圖片加載機制,選擇第三方開源庫也是理所固然。通常狀況,直接用第三方庫加載圖片便可,幾乎不用作額外處理,固然複雜的狀況就須要結合第三方庫進行優化處理了。七牛雲存儲
2.按照不一樣的圖片控件尺寸去加載圖片,能夠減小內存開銷,節省資源,提升加載速度。例如微信朋友圈,在列表界面加載縮略小圖,點擊查看時才加載大圖。咱們項目開發時,圖片上傳與存儲用的是七牛雲存儲,而七牛雲存儲自己提供強大的圖片處理API,能夠根據請求的連接,獲取不一樣尺寸的圖片,方便開發們結合自身項目需求,實現最優圖片尺寸加載方案。七牛圖片處理API文檔地址放在文章最底下,有興趣的能夠了解下。緩存
3.今天的主角LruCache,什麼是LruCache?LruCache是android提供的一個緩存工具類,其算法是最近最少使用算法。它把最近使用的對象用「強引用」存儲在LinkedHashMap中,而且把最近最少使用的對象在緩存值達到預設定值以前就從內存中移除。其在API12被引進,低版本能夠用support包中的類。因此咱們用LruCache來緩存加載的Bitmap,當內存低於咱們設定的值後,LruCache便會自動幫咱們回收用不到的資源。微信
具體緣由已經分析,廢話很少說,直接上代碼app
一、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; } }
二、LruCacheUtils使用ide
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)); }
三、圖片加載方法
/** * 加載圖片 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); } }; }
優化完成後,運行程序,在Android studio中找到Monitors一欄,進行圖片查看測試,就能清楚的看到內存變化以及釋放的過程啦。優化以前是直接使用Glide進行加載圖片,內存曾一路飆升到200M,而且很難釋放。加了縮略圖以及LruCache優化後,內存一直保持在40M-80M之間。測試結果,基本上沒有重現過OOM的狀況。
PS:建議app中全部加載過的bitmap都直接扔到LruCacheUtils中進行緩存,在bitmap沒有使用時,方便系統對齊回收。調用上面代碼前,請記得集成Glide開源庫哦。若是你使用以上方法進行圖片加載優化,仍是會出現OOM的話,那就說明......你可能要換手機了……