Android—大圖or多圖載入解決方案(完美解決OOM問題)

來源:互聯網
上載者:User

標籤:android   解決方案   應用程式   oom   

在開發應用的時候,很多時候都會涉及大量圖片的載入和高精度圖片的載入,這兩種操作都是會導致應用程式OOM(OutOfMemory)的問題發生,合理的圖片載入和圖片記憶體管理就是必須解決的問題,以下將提供一個比較完善的技術方案,解決這兩個問題。


首先,我們必須明確為什麼會發生OOM(OutOfMemory)的問題,其原因就是因為在APP運行過程中,所使用的系統記憶體超出了當前APP的最大可用記憶體,就發生了OOM的問題。下面,我們來估算一下在一台中高檔的手機上面,載入多少圖片會導致OOM:假設系統分配給APP的最大可用記憶體為32M,載入一張512*512解析度的圖片,會佔用2M的記憶體空間,這樣,在APP中載入16張圖片,就會出現OOM,事實上,當載入10張圖片以上,都極容易導致OOM,因為APP運行中還是會佔用記憶體的。(PS:圖片佔用記憶體計算:Android中Bitmap的預設載入使用ARGB_8888,每個像素會佔用4byte,因為每個像素有兩個Chanel,因此一個512*512的圖片,無論什麼格式,載入進入記憶體都佔用512*512*4*2=2MB,所以,Android圖片佔用記憶體大小,只與圖片的解析度(像素)以及載入使用的色彩模式有關)


要解決OOM的問題,從兩方面進行最佳化:1.合理載入資源2.合理回收資源


合理載入資源

合理載入資源,既如果展示圖片的ImageView只有128*96的像素大小,這時候把一張1024*768的圖片完全載入到記憶體中,很明顯是錯誤的行為。這個時候,就需要把要載入的圖片進行壓縮載入,就是合理地載入資源。

下面,來進行圖片的壓縮講解,設定BitmapFactory.Options中inSampleSize的值就可以實現等比例壓縮。比如我們有一張2048*1536像素的圖片,將inSampleSize的值設定為4,就可以把這張圖片壓縮成512*384像素。原本載入這張圖片需要佔用26M的記憶體,壓縮後就只需要佔用1.5M了。下面的方法可以根據傳入的寬和高,計算出合適的inSampleSize值:

public static int calculateInSampleSize(BitmapFactory.Options options,int reqWidth, int reqHeight) {// 源圖片的高度和寬度final int height = options.outHeight;final int width = options.outWidth;int inSampleSize = 1;if (height > reqHeight || width > reqWidth) {// 計算出實際寬高和目標寬高的比率final int heightRatio = Math.round((float) height / (float) reqHeight);final int widthRatio = Math.round((float) width / (float) reqWidth);// 選擇寬和高中最小的比率作為inSampleSize的值,這樣可以保證最終圖片的寬和高// 一定都會大於等於目標的寬和高。inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;}return inSampleSize;}

計算出合適的縮放比例後,接著進行圖片的實際壓縮操作:

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,        int reqWidth, int reqHeight) {// 第一次解析將inJustDecodeBounds設定為true,來擷取圖片大小    final BitmapFactory.Options options = new BitmapFactory.Options();    options.inJustDecodeBounds = true;    BitmapFactory.decodeResource(res, resId, options);    // 調用上面定義的方法計算inSampleSize值    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);    // 使用擷取到的inSampleSize值再次解析圖片    options.inJustDecodeBounds = false;    return BitmapFactory.decodeResource(res, resId, options);}
經過以上的兩步操作,即可實現合理的載入圖片資源。


合理回收資源


合理回收資源,既對載入在記憶體中的圖片資源進行合理的回收,避免因為不再使用的圖片資源還留存在記憶體中的情況出現。而要實現合理回收資源,最核心的一個類就是:LruCache,這個類非常適用於儲存圖片記憶體,它的主要演算法原理是把最近使用的對象用強引用儲存在 LinkedHashMap 中,並且把最近最少使用的對象在緩衝值達到預設定值之前從記憶體中移除。

下面給出具體的使用方法:

private LruCache<String, Bitmap> mMemoryCache;@Overrideprotected void onCreate(Bundle savedInstanceState) {// 擷取到可用記憶體的最大值,使用記憶體超出這個值會引起OutOfMemory異常。// LruCache通過建構函式傳入緩衝值,以KB為單位。int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);// 使用最大可用記憶體值的1/8作為緩衝的大小。int cacheSize = maxMemory / 8;mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {@Overrideprotected int sizeOf(String key, Bitmap bitmap) {// 重寫此方法來衡量每張圖片的大小,預設返回圖片數量。return bitmap.getByteCount() / 1024;}};}public void addBitmapToMemoryCache(String key, Bitmap bitmap) {if (getBitmapFromMemCache(key) == null) {mMemoryCache.put(key, bitmap);}}public Bitmap getBitmapFromMemCache(String key) {return mMemoryCache.get(key);}

只要確保整個APP的圖片資源的使用,都是通過addBitmapToMemoryCache和getBitmapFromMemCache來進行,即可避免OOM的出現。


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.