Android--Bitmap效能最佳化

來源:互聯網
上載者:User

標籤:

今天做項目,發現需要顯示一張超大圖片,處理過後,還有561Kb

     載入的時候,就crash --- OOM

     shortMsg:java.lang.OutOfMemoryError

     longMsg:java.lang.OutOfMemoryError: bitmap size exceeds VM budget

     stackTrace:java.lang.OutOfMemoryError: bitmap size exceeds VM budget
     at android.graphics.Bitmap.nativeCreate(Native Method)
     at android.graphics.Bitmap.createBitmap(Bitmap.java:477)
     at android.graphics.Bitmap.createBitmap(Bitmap.java:444)
     at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:349)
     at android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:512)
     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:487)
     at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:336)

     

      代碼如下:

  //this line will lead to OOM 

      detailView=(ImageView)findViewById(R.id.detailView);      detailView.setBackgroundResource(R.drawable.more_info);

 

       換成這種:

      detailView.setImageResource(R.drawable.more_info); //也同樣會OOM

 

       

       後來找到了solution:

    /**     * 以最省記憶體的方式讀取本地資源的圖片     * @param context     *@param resId     * @return     */    public static Bitmap readBitMap(Context context, int resId){        BitmapFactory.Options opt = new BitmapFactory.Options();        opt.inPreferredConfig = Bitmap.Config.RGB_565;        opt.inPurgeable = true;        opt.inInputShareable = true;        //擷取資源圖片        InputStream is = context.getResources().openRawResource(resId);        return BitmapFactory.decodeStream(is,null,opt);    }

 

    取得bitmap之後,再 detailView.setImageBitmap(pdfImage); 就ok了!      

 

   那是為什麼,會導致oom呢:

         原來當使用像

    imageView.setBackgroundResource,

    imageView.setImageResource,

    BitmapFactory.decodeResource  這樣的方法來設定一張大圖片的時候

         這些函數在完成decode後,最終都是通過java層的createBitmap來完成的,需要消耗更多記憶體。

         因此,

    1、改用先通過BitmapFactory.decodeStream方法,建立出一個bitmap

    2、再將其設為ImageView的 source,decodeStream最大的秘密在於其直接調用JNI>>nativeDecodeAsset()來完成decode,無需再使用java層的createBitmap,從而節省了java層的空間。

  如果在讀取時加上圖片的Config參數,可以跟有效減少載入的記憶體,從而跟有效阻止拋out of Memory異常。

        另外,需要特別注意: 

    decodeStream是直接讀取圖片資料的位元組碼的, 不會根據機器的各種解析度來自動適應,使用了decodeStream之後,需要在hdpi和mdpi,ldpi中配置相應的圖片資源,否則在不同解析度機器上都是同樣大小(像素點數量),顯示出來的大小就不對了。

 


在載入圖片資源時,可採用以下一些方法來避免OOM的問題: 
1,在Android 2.3.3以及之前,建議使用Bitmap.recycle()方法,及時釋放資源。 

 

1,在Android 3.0開始

可設定BitmapFactory.options.inBitmap值,(從緩衝中擷取)達到重用Bitmap的目的。如果設定,則inPreferredConfig屬性值會被重用的Bitmap該屬性值覆蓋。 

2,通過設定Options.inPreferredConfig值來降低記憶體消耗: 
     ARGB_8888: 每個像素4位元組. 共32位。   它為預設值
     Alpha_8: 只儲存透明度,共8位,1位元組。 
     ARGB_4444: 共16位,2位元組。 
     RGB_565:共16位,2位元組。 
     如果不需要透明度,可把預設值ARGB_8888改為RGB_565,節約一半記憶體。 
3,通過設定Options.inSampleSize 對大圖片進行壓縮,可先設定Options.inJustDecodeBounds,擷取Bitmap的外圍資料,寬和高等。然後計算壓縮比例,進行壓縮。 
4,設定Options.inPurgeable和inInputShareable:讓系統能及時回收記憶體。 
       1、inPurgeable:

    (1)設定為True,則使用BitmapFactory建立的Bitmap用於儲存Pixel的記憶體空間,在系統記憶體不足時可以被回收,當應用需要再次訪問該Bitmap的Pixel時,系統會再次調用BitmapFactory 的decode方法重建Bitmap的Pixel數組。 
     (2)設定為False時,表示不能被回收。 

   2、inInputShareable:設定是否深拷貝,與inPurgeable結合使用,inPurgeable為false時,該參數無意義。 
                                  True:  share  a reference to the input data(inputStream, array,etc)

              False :a deep copy
5,使用decodeStream代替其他decodeResource,setImageResource,setImageBitmap等方法來載入圖片。 
     區別: 
      (1)decodeStream直接讀取圖片位元組碼,調用nativeDecodeAsset/nativeDecodeStream來完成decode。無需使用Java空間的一些額外處理過程,節省dalvik記憶體。但是由於直接讀取位元組碼,沒有處理過程,因此不會根據機器的各種解析度來自動適應,需要在hdpi,mdpi和ldpi中分別配置相應的圖片資源,否則在不同解析度機器上都是同樣的大小(像素點數量),顯示的實際大小不對。 
      decodeResource會在讀取完圖片資料後,根據機器的解析度,進行圖片的適配處理,導致增大了很多dalvik記憶體消耗。 

       decodeStream調用過程: decodeStream(InputStream,Rect,Options) -> nativeDecodeAsset/nativeDecodeStream 
       decodeResource調用過程:即finishDecode之後,調用額外的Java層的createBitmap方法,消耗更多dalvik記憶體。 
             decodeResource(Resource,resId,Options)  -> decodeResourceStream (設定Options的inDensity和inTargetDensity參數)  -> decodeStream() (在完成Decode後,進行finishDecode操作) 
             finishDecode() -> Bitmap.createScaleBitmap()(根據inDensity和inTargetDensity計算scale) -> Bitmap.createBitmap() 

以上方法的組合使用,合理避免OOM錯誤。 
                    

 

Android--Bitmap效能最佳化

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.