Android加載大圖片OOM異常解決


項目用到加載大圖片,app老是出現OOM異常,總結了幾點經驗,供參考。

1、手動干涉dalvik的堆內存處理效率:

1     private final static float TARGET_HEAP_UTILIZATION = 0.75f;
2     //for same activity
3     public void onCreate()
4     {
5         …………
6         VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION); 
7         …………
8     }

2、手動指定Android堆大小:

1     private final static int CWJ_HEAP_SIZE = 6* 1024* 1024 ; 
2     //for same activity
3     public void onCreate()
4     {
5         …………
6         VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE); //設置最小heap內存為6MB大小。當然對於內存吃緊來說還可以通過手動干涉GC去處理  
7         …………
8     }

3、手動指定回收內存,指定gc:

1         if(bitmap!=null && !bitmap.isRecycled())
2         {
3             bitmap.recycle();
4             System.gc();
5         }

4、圖片必須進行縮放,不然多半會出OOM:

 1     /**
 2      * @param url
 3      *            圖片的url
 4      * @param sc
 5      *            ,顯示的像素大小
 6      * @return 返回指定RUL的縮略圖
 7      * 
 8      * @author jevan 2012-7-3
 9      * 
10      */
11     public static Bitmap loadImageFromUrl(String url, int sc)
12     {
13 
14         URL m;
15         InputStream i = null;
16         BufferedInputStream bis = null;
17         ByteArrayOutputStream out = null;
18 
19         if (url == null)
20             return null;
21         try
22         {
23             m = new URL(url);
24             i = (InputStream) m.getContent();
25             bis = new BufferedInputStream(i, 1024 * 4);
26             out = new ByteArrayOutputStream();
27             int len = 0;
28 
29             while ((len = bis.read(isBuffer)) != -1)
30             {
31                 out.write(isBuffer, 0, len);
32             }
33             out.close();
34             bis.close();
35         } catch (MalformedURLException e1)
36         {
37             e1.printStackTrace();
38             return null;
39         } catch (IOException e)
40         {
41             e.printStackTrace();
42         }
43         if (out == null)
44             return null;
45         byte[] data = out.toByteArray();
46         BitmapFactory.Options options = new BitmapFactory.Options();
47         options.inJustDecodeBounds = true;
48         BitmapFactory.decodeByteArray(data, 0, data.length, options);
49         options.inJustDecodeBounds = false;
50         int be = (int) (options.outHeight / (float) sc);
51         if (be <= 0)
52         {
53             be = 1;
54         } else if (be > 3)
55         {
56             be = 3;
57         }
58         options.inSampleSize = be;
59         Bitmap bmp =null;
60         try
61         {
62             bmp = BitmapFactory.decodeByteArray(data, 0, data.length, options); //返回縮略圖
63         } catch (OutOfMemoryError e)
64         {
65             // TODO: handle exception
66             MainActivity.print("Tile Loader (241) Out Of Memory Error " + e.getLocalizedMessage()); 
67         
68             System.gc();
69             bmp =null;
70         }
71         return bmp;
72     }

把上面幾條全部用上,OOM的異常基本上能完全避免!!!

 

以下內容為轉載,收藏。

 1     //我們在BitmapManager.instance().decodeFile對圖片進行解碼,生成Bitmap的時候,我們會發現很多大圖片會報OutOfMemoryError的錯誤,這個時候我們需要改變options里面的一些參數來解決這個問題,不然我們程序就跑不下去了。最簡單的方法就是改變options.inSampleSize這個參數,把它增大,就可以解決很多圖片OutOfMemoryError的問題。
 2     //下面是一個使用了這個方式的代碼
 3     public static Bitmap makeBitmap(String path, int minSideLength, int maxNumOfPixels, BitmapFactory.Options options)
 4     {
 5         Bitmap b = null;
 6         Log.i(TAG, "makeBitmap : path = " + path);
 7         if (path == null)
 8             return null;
 9         File f = new File(path);
10 
11         //try {
12         // b = BitmapManager.instance().decodeFile(f, null);
13         //} catch (OutOfMemoryError ex) {
14         // Log.e(TAG, "Got oom exception, we may try one more time, using Options:" + ex.getMessage());
15         if (options == null)
16         {
17             options = new BitmapFactory.Options();
18         }
19 
20         try
21         {
22             options.inJustDecodeBounds = true;
23             BitmapManager.instance().decodeFile(f, options);
24             if (options.mCancel || options.outWidth == -1 || options.outHeight == -1)
25             {
26                 return null;
27             }
28             options.inSampleSize = computeSampleSize(options, minSideLength, maxNumOfPixels);
29             options.inJustDecodeBounds = false;
30             options.inDither = true;
31             options.inPreferredConfig = null;//Bitmap.Config.ARGB_8888;
32 
33             b = BitmapManager.instance().decodeFile(f, options);
34         } catch (OutOfMemoryError ex2)
35         {
36             Log.e(TAG, "Got oom exception when retry the 2nd time,options.inSampleSize= " + options.inSampleSize + " minSideLength = "
37                     + minSideLength + " maxNumOfPixels =" + maxNumOfPixels, ex2);
38             try
39             {
40                 options.inSampleSize += 1;
41                 options.inJustDecodeBounds = false;
42                 options.inDither = true;
43                 options.inPreferredConfig = null;
44                 b = BitmapManager.instance().decodeFile(f, options);
45             } catch (OutOfMemoryError e)
46             {
47                 Log.e(TAG, "Got oom exception when retry the 2nd time,options.inSampleSize= " + options.inSampleSize + " minSideLength = "
48                         + minSideLength + " maxNumOfPixels =" + maxNumOfPixels, e);
49                 try
50                 {
51                     options.inSampleSize += 1;
52                     options.inJustDecodeBounds = false;
53                     options.inDither = true;
54                     options.inPreferredConfig = null;
55                     b = BitmapManager.instance().decodeFile(f, options);
56                 } catch (OutOfMemoryError ex)
57                 {
58                     Log.e(TAG, "Got oom exception when retry the 2nd time,options.inSampleSize= " + options.inSampleSize
59                             + " minSideLength = " + minSideLength + " maxNumOfPixels =" + maxNumOfPixels, ex);
60                     return null;
61                 }
62             }
63         }
64 
65         //} 
66         return b;
67     }
 1     //另外一處代碼
 2     public static Bitmap getBitpMap(InputStream is)
 3     {
 4         ParcelFileDescriptor pfd;
 5         try
 6         {
 7             pfd = getContentResolver().openFileDescriptor(uri, "r");
 8         } catch (IOException ex)
 9         {
10             return null;
11         }
12         java.io.FileDescriptor fd = pfd.getFileDescriptor();
13         BitmapFactory.Options options = new BitmapFactory.Options();
14         //先指定原始大小   
15         options.inSampleSize = 1;
16         //只進行大小判斷   
17         options.inJustDecodeBounds = true;
18         //調用此方法得到options得到圖片的大小   
19         BitmapFactory.decodeFileDescriptor(fd, null, options);
20         //BitmapFactory.decodeStream(is, null, options);
21         //我們的目標是在800pixel的畫面上顯示。   
22         //所以需要調用computeSampleSize得到圖片縮放的比例   
23         options.inSampleSize = computeSampleSize(options, 800);
24         //OK,我們得到了縮放的比例,現在開始正式讀入BitMap數據   
25         options.inJustDecodeBounds = false;
26         options.inDither = false;
27         options.inPreferredConfig = Bitmap.Config.ARGB_8888;
28 
29         //根據options參數,減少所需要的內存   
30         //        Bitmap sourceBitmap = BitmapFactory.decodeFileDescriptor(fd, null, options);
31         Bitmap sourceBitmap = BitmapFactory.decodeStream(is, null, options);
32         return sourceBitmap;
33     }
34 
35     //這個函數會對圖片的大小進行判斷,並得到合適的縮放比例,比如2即1/2,3即1/3   
36     static int computeSampleSize(BitmapFactory.Options options, int target)
37     {
38         int w = options.outWidth;
39         int h = options.outHeight;
40         int candidateW = w / target;
41         int candidateH = h / target;
42         int candidate = Math.max(candidateW, candidateH);
43         if (candidate == 0)
44             return 1;
45         if (candidate > 1)
46         {
47             if ((w > target) && (w / candidate) < target)
48                 candidate -= 1;
49         }
50         if (candidate > 1)
51         {
52             if ((h > target) && (h / candidate) < target)
53                 candidate -= 1;
54         }
55         //if (VERBOSE)
56         Log.v(TAG, "for w/h " + w + "/" + h + " returning " + candidate + "(" + (w / candidate) + " / " + (h / candidate));
57         return candidate;
58     }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM