Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 高效加載大圖片避免OOM

Android 高效加載大圖片避免OOM

編輯:關於Android編程

 

我們項目中經常會加載圖片,有時候如果加載圖片過多的話,小則導致程序很卡,重則OOM導致App掛了,今天翻譯https://developer.android.com/training/displaying-bitmaps/index.html,學習Google高效加載大圖片的方法。

圖片有各種形狀和大小,但在大多數情況下,這些圖片都會大於我們程序所需要的大小。比如說系統圖片庫裡展示的圖片大都是用手機攝像頭拍出來的,這些圖片的分辨率會比我們手機屏幕的分辨率高得多。大家應該知道,我們編寫的應用程序都是有一定內存限制的,程序占用了過高的內存就容易出現OOM(OutOfMemory)異常。我們可以通過下面的代碼看出每個應用程序最高可用內存是多少。

 

[java] view plaincopyprint?
  1. int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024/1024);

    現在大部分手機都是32M,既然知道了每個app分配的內存,所以就要計算好加載多少圖片而不導致出現OOM,所以要計算每張圖片所占用的內存是多少。

    Android中計算一張圖片所占內存大小方法:圖片長*寬*所占像素字節數,而像素字節數Android中也就四種,

    1:ALPHA_8 占1個字節

    2:ARGB_4444 占2個字節

    3:ARGB_8888 占4個字節

    4:RGB_565 占2個字節

     

    :ARGB指的是一種色彩模式,裡面A代表Alpha,R表示red,G表示green,B表示blue,其實所有的可見色都是紅綠藍組成的,所以紅綠藍又稱為三原色。 A  R  G  B
    透明度 紅色 綠色 藍色

    而這些字節數是可以通過bitmap對象去設置的,bitmap.setConfig(Bitmap.Config.ARGB_4444);如果這是個定值,那麼要改變一個張圖片的大小,就只能改寬或者高了,如果只改高,寬不變的話,就會造成圖片變形,因此一般都是一起改動,所以圖片要縮放,而縮放時根據屏幕的寬和高來縮放的,因為Android設備很多,每個屏幕的寬和高也不一樣,這樣就能達到加載大圖片避免OOM。

    [java] view plaincopyprint?
    1. BitmapFactory這個類提供了多個解析方法(decodeByteArray, decodeFile, decodeResource等)用於創建Bitmap對象,我們應該根據圖片的來源選擇合適的方法。比如SD卡中的圖片可以使用decodeFile方法,網絡上的圖片可以使用decodeStream方法,資源文件中的圖片可以使用decodeResource方法。這些方法會嘗試為已經構建的bitmap分配內存,這時就會很容易導致OOM出現。為此每一種解析方法都提供了一個可選的BitmapFactory.Options參數,將這個參數的inJustDecodeBounds屬性設置為true就可以讓解析方法禁止為bitmap分配內存,返回值也不再是一個Bitmap對象,而是null。雖然Bitmap是null了,但是BitmapFactory.Options的outWidth、outHeight和outMimeType屬性都會被賦值。這個技巧讓我們可以在加載圖片之前就獲取到圖片的長寬值和MIME類型,從而根據情況對圖片進行壓縮。如下代碼所示: [java] view plaincopyprint?
      1. BitmapFactory.Options options = new BitmapFactory.Options();
      2. options.inJustDecodeBounds = true;
      3. BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
      4. int imageHeight = options.outHeight;
      5. int imageWidth = options.outWidth;
      6. String imageType = options.outMimeType; 比如一張480*800的圖片直接加載到內存中,如果圖片很多那就很容易造成OOM,那就必須壓縮,比如按1/8進行壓縮,壓縮後得到的60*100,如果從服務器獲取的圖片規格不一樣,那壓縮後現在在ImageView上肯定不一樣,因為ImageView寬和高肯定是設置成wrap_content。

        現在寫個Demo縮放圖片代碼如下

         

        [java] view plaincopyprint?
        1. package com.jackie.bitmapdemo;
        2.  
        3. import android.app.Activity;
        4. import android.content.res.Resources;
        5. import android.graphics.Bitmap;
        6. import android.graphics.BitmapFactory;
        7. import android.os.Bundle;
        8. import android.widget.ImageView;
        9.  
        10. public class MainActivity extends Activity {
        11. private ImageView imageView;
        12. @Override
        13. protected void onCreate(Bundle savedInstanceState) {
        14. super.onCreate(savedInstanceState);
        15. setContentView(R.layout.activity_main);
        16. imageView = (ImageView) findViewById(R.id.iv);
        17. Bitmap bitmap = decodeSampledBitmapFromResource(getResources(), R.drawable.b, 60, 100);
        18. iv.setImageBitmap(bitmap);
        19. }
        20.  
        21. public static int calculateInSampleSize(BitmapFactory.Options options,
        22. int reqWidth, int reqHeight) {
        23. // 源圖片的高度和寬度
        24. final int height = options.outHeight;
        25. final int width = options.outWidth;
        26. int inSampleSize = 1;
        27. if (height > reqHeight || width > reqWidth) {
        28. // 計算出實際寬高和目標寬高的比率
        29. final int heightRatio = Math.round((float) height / (float) reqHeight);
        30. final int widthRatio = Math.round((float) width / (float) reqWidth);
        31. //計算縮放比例
        32. inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        33. }
        34. return inSampleSize;
        35. }
        36. public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
        37. int reqWidth, int reqHeight) {
        38. // 第一次解析將inJustDecodeBounds設置為true,來獲取圖片大小
        39. final BitmapFactory.Options options = new BitmapFactory.Options();
        40. options.inJustDecodeBounds = true;
        41. BitmapFactory.decodeResource(res, resId, options);
        42. // 調用上面定義的方法計算inSampleSize值
        43. options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
        44. // 使用獲取到的inSampleSize值再次解析圖片
        45. options.inJustDecodeBounds = false;
        46. return BitmapFactory.decodeResource(res, resId, options);
        47. }
        48.  
        49. } 計算縮放比例一般有2種做法:

           

          1:根據屏幕寬和高來縮放圖片

          2:根據要縮放後的寬和高來縮放,上面的例子就是根據這種。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved