天天看點

Android開發中 頁面加載一張超大圖檔(561kb)時出現OOM

今天做項目,發現需要顯示一張超大圖檔,處理過後,還有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)

      代碼如下:

      detailview=(imageview)findviewbyid(r.id.detailview);

      detailview.setbackgroundresource(r.drawable.more_info);//this line will lead to oom 

       換成這種:

      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來完成的,需要消耗更多記憶體。

         是以,改用先通過bitmapfactory.decodestream方法,建立出一個bitmap,再将其設為imageview的 source,decodestream最大的秘密在于其直接調用jni>>nativedecodeasset()來完成decode,無需再使用java層的createbitmap,進而節省了java層的空間。如果在讀取時加上圖檔的config參數,可以跟有效減少加載的記憶體,進而跟有效阻止抛out of memory異常。

        另外,需要特别注意: 

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

繼續閱讀