Android加載圖片時,對于分辨率小,配置低的機子,很容易發生OutOfMemoryError。手機的內存比圖片的大很多,怎么會這樣?
在設置Android虛擬機的內存時:
RAM:模擬器的內存空間
VM Heap:dalvik虛擬機最大占用內存,也就是單個進程的最大占用內存。
VM Heap高配的手機,可能有32M,64M,128M,而低配的手機,一般是16M,分辨率越大的手機,一般分配的也比較多。
Android系統對dalvik的vm heapsize作了硬性限制,當java進程申請的java空間超過閾值時,就會拋出OOM異常。也就是說RAM充足也會發生OOM的異常。
--------------------
VM Heap大小16mb,當應用加載一張大圖時,加載圖片所需要的內存空間不是按照圖片大小算的,而是按照圖片的像素點來算的。
圖片像素點計算:
1張叫juhua.jsp的圖片,大小1.27MB,分辨率:3840*2160,24位。
* Android保存圖片像素信息,是用ARGB保存
?* A:0-255,需要一個長度為8的二進制數字,占用1個字節
?* R:0-255,需要一個長度為8的二進制數字,占用1個字節
?* G:0-255,需要一個長度為8的二進制數字,占用1個字節
?* B:0-255,需要一個長度為8的二進制數字,占用1個字節
3840*2160*4=33177600字節/1024/1024=31.640MB
超過了VM Heap的16MB,報內存溢出
10-27 06:16:27.645: I/dalvikvm-heap(1894): Forcing collection of SoftReferences for 33177612-byte allocation
10-27 06:16:27.645: E/dalvikvm-heap(1894): Out of memory on a 33177612-byte allocation.
10-27 06:16:27.655: E/AndroidRuntime(1894): Caused by: java.lang.OutOfMemoryError
10-27 06:16:27.645: E/dalvikvm-heap(1894): Out of memory on a 33177612-byte allocation.
10-27 06:16:27.655: E/AndroidRuntime(1894): Caused by: java.lang.OutOfMemoryError
************************************
解決方法:
按比例縮小圖片,再加載。
現有手機屏幕分辨率 320*480
寬比:3840/320=12
高比:2160/480=4
選擇比例大的數字12
縮放后再設置,就不會溢出了。
31.640MB/12=2.64mb
代碼例子:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity" ><Buttonandroid:id="@+id/btn1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="點擊加載大圖片(OOO)"android:onClick="loadPic"/><Buttonandroid:id="@+id/btn2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@id/btn1"android:text="點擊縮放加載大圖片"android:onClick="scaleLoadPic"/><ImageView android:id="@+id/iv_pic"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@id/btn2"/></RelativeLayout>
package com.example.loadbigpic;import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.os.Bundle;
import android.view.Display;
import android.view.View;
import android.widget.ImageView;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void loadPic(View v){/** BitmapFactory.decodeResource(?,?)* 這個帶兩個參數的方法:第一個參數是包含你要加載的位圖資源文件的對象(一般寫成 getResources()就ok了);* 第二個時你需要加載的位圖資源的Id。BitmapFactory.decodeResource(?,?,?)帶三個參數的方法:前兩個和上面的方法一樣。第三個參數應該是對你要加載的位圖是否需要完整顯示,如果你只需要部分,可以在這里定制。*/Bitmap bm=BitmapFactory.decodeResource(getResources(),R.drawable.juhua);ImageView iv_pic=(ImageView) findViewById(R.id.iv_pic);iv_pic.setImageBitmap(bm);}public void scaleLoadPic(View v){Options opts=new Options();//默認為false,設為true,則decoder返回null,//即BitmapFactory.decodeResource(getResources(),R.drawable.juhua,opts);返回null//但會返回圖片的參數的信息到Options對象里//不解析圖片到內存里opts.inJustDecodeBounds=true;BitmapFactory.decodeResource(getResources(),R.drawable.juhua,opts);//獲取圖片的寬,高int imageWidth=opts.outWidth;int imageHeigth=opts.outHeight;//獲取屏幕的高寬Display dp=getWindowManager().getDefaultDisplay();//在高版本里有新的方法獲取,但圖片加載是常用功能,要兼容低版本,所以過時了也用int screenWidth=dp.getWidth();int screenHeight=dp.getHeight();//計算縮放比例int scale=1;int scaleWidth=imageWidth/screenWidth;int scaleHeight=imageHeigth/screenHeight;//取縮放比例,取那個大的值if(scaleWidth>=scaleHeight && scaleWidth>=1){scale=scaleWidth;}else if(scaleWidth<scaleHeight && scaleHeight>=1){scale=scaleHeight;}//設置縮放比例opts.inSampleSize=scale;opts.inJustDecodeBounds=false;Bitmap bm=BitmapFactory.decodeResource(getResources(),R.drawable.juhua,opts);ImageView iv_pic=(ImageView) findViewById(R.id.iv_pic);iv_pic.setImageBitmap(bm);}}