1. 程式人生 > >Android 載入圖片過程導致記憶體溢位(Out Of Memory)

Android 載入圖片過程導致記憶體溢位(Out Of Memory)

載入圖片的時候,啪啪啪就OOM了。
解決圖片OOM之前,先來了解一下一張圖片記憶體佔用的相關因素——圖片質量,圖片尺寸,填充區域

圖片質量

質量就是圖片大小(多少MB,多少KB)。相對情況下圖片越大,佔用記憶體越大

圖片尺寸

圖片尺寸=圖片的寬高,相對情況下寬高越大,佔用記憶體越大

填充區域

填充區域就是圖片顯示在螢幕上的大小,可以理解為ImageView的大小。相對情況下寬高越大,佔用記憶體越小。 (有些人一直錯誤理解為imageView越小,佔記憶體越小。舉個例子,一張10MB原本放在一個10000*10000的容器裡,他沒什麼壓力。把它扔進一個10*10的容器裡,能不出事嗎?一噸水在一個大缸子裡好好的,你換一個礦泉水瓶去裝一噸水,能不溢位?)
PS:因為專案裡,imageView的大小基本是固定的,所以不從這個方向去考慮減少記憶體。這裡提到填充區域,因為有不少人是頭像設定的時候引發OOM,列表的頭像一般都是30*30到60*60,區域很小,有些人上傳了原始尺寸圖片,來源各種各種,有些設定幾千x幾千,然後就OOM了。

瞭解了記憶體佔用相關要素以後,解決方案就很直接了,就是去改變這些相關要素。

1 圖片質量壓縮

    private Bitmap compressImage(Bitmap image) {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//質量壓縮方法,這裡100表示不壓縮,把壓縮後的資料存放到baos中  
        int options = 100;
        while ( baos.toByteArray().length / 1024
>100) { //迴圈判斷如果壓縮後圖片是否大於100kb,大於繼續壓縮 baos.reset();//重置baos即清空baos image.compress(Bitmap.CompressFormat.JPEG, options, baos);//這裡壓縮options%,把壓縮後的資料存放到baos中 options -= 10;//每次都減少10 } ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把壓縮後的資料baos存放到ByteArrayInputStream中
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream資料生成圖片 return bitmap; }

圖片壓縮的方法網上很多,我也是網上copy的,一般專案裡就直接使用Glide壓縮了

2 重新設定圖片大小

    public Bitmap zoomImg(Bitmap bm, int newWidth ,int newHeight){
        // 獲得圖片的寬高   
        int width = bm.getWidth();
        int height = bm.getHeight();
        // 計算縮放比例   
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        // 取得想要縮放的matrix引數   
        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth, scaleHeight);
        // 得到新的圖片
        Bitmap newbm = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true);
        return newbm;
    }

建議使用三方庫,比如glide裡就有個.override(width,height)的方法,在算出bitmap等比例縮小到imageView上顯示的寬高,然後呼叫重新設定寬高的方法。

3 圖片記憶體回收

上面說的兩種方法是在圖片顯示的時候減少記憶體。而圖片使用過後呢,關閉Activity之後,圖片有一段時間是不會馬上回收的,可以呼叫一下recycle()方法。又或者你是列表分頁場景,可以在上分頁後,清除掉上分頁中
imgURl的快取。具體參照業務需求,有些需求本身就是要求各種快取來節省流量的。

圖片壓縮和圖片重設寬高建議直接用三方庫啊,Glide,Picasso都比較常見了。