避免記憶體不足的異常
因為相機所拍出的相片畫質如果比較高,在處理圖片縮小時很有可能會遇到VM記憶體不足的問題。而Android本身有提供幾個參數。首先是
inSampleSize
If set to a value > 1, requests the decoder to subsample the original
image, returning a smaller image to save memory. The sample size is
the number of pixels in either dimension that correspond to a single
pixel in the decoded bitmap. For example, inSampleSize == 4 returns
an image that is 1/4 the width/height of the original, and 1/16 the
number of pixels. Any value <= 1 is treated the same as 1. Note: the
decoder will try to fulfill this request, but the resulting bitmap
may have different dimensions that precisely what has been requested.
Also, powers of 2 are often faster/easier for the decoder to honor.
主要是說,如果將值設定為 1 以上的數值,系統便會回傳一個比原始圖像還要小的圖像,目的是為了減少記憶體的使用,相關的邏輯在原文中也有述說。
另一個是
inJustDecodeBounds
If set to true, the decoder will return null (no bitmap), but the out... fields will still be set, allowing the caller to query the bitmap without having to allocate the memory for its pixels.
如果將此值設為 true 的話,系統在decode時不會直接回傳一個Bitmap的物件,但我們可以取得原始圖像的高度和寬度等相關資訊。這邊是為了防止記憶體不足,利用取回的資訊,去計算出 inSampleSize 的數值。
Bitmap recycle
Free the native object associated with this bitmap, and clear the
reference to the pixel data.
這個相當的重要。如果你所處理的圖像很多,記得把已經需要用到的 Bitmap 物件 recycle ,以釋放記憶體。
實際用法如下
public class CameraRunActivity extends Activity implements Callback, OnClickListener { private static final String TAG = CameraRunActivity.class.getSimpleName(); private SurfaceView surfaceview; private SurfaceHolder surfaceholder; private Camera myCamera; private ImageView camera_action; private Bitmap finalBMP; private final int HANDLER_OF_PROCESS = 0; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.camera_run); setRequestedOrientation(1); // 定義 Layout 中的 SurfaceView surfaceview = (SurfaceView) findViewById(R.id.surfaceview); surfaceholder = surfaceview.getHolder(); // 定義 SurfaceView Holder 相關的處理 surfaceholder.addCallback(this); surfaceholder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); // 實際觸發拍照的物件 camera_action = (ImageView) findViewById(R.id.camera_action); camera_action.setOnClickListener(this); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { Camera.Parameters parameters = myCamera.getParameters(); // 開啟自動對焦的模式 parameters.setFocusMode("auto"); // 設定輸出的圖像格式 parameters.setPictureFormat(PixelFormat.JPEG); myCamera.setParameters(parameters); // 同步 SurfaceView 與 Camera myCamera.startPreview(); isCameraOpen = true; } @Override public void surfaceCreated(SurfaceHolder holder) { try { myCamera = Camera.open(); myCamera.setPreviewDisplay(surfaceholder); // 將相機轉 90 度,因為手機要保持直立 myCamera.setDisplayOrientation(90); } catch (IOException e) { myCamera.release(); myCamera = null; } } @Override public void surfaceDestroyed(SurfaceHolder holder) { myCamera.stopPreview(); isCameraOpen = false; myCamera.release(); myCamera = null; } @Override public void onClick(View v) { switch (v.getId()) { case R.id.camera_action : isCameraOpen = false; // 先觸發自動對焦,然後再拍照 myCamera.autoFocus(autoFacusCallback); break; } } private ShutterCallback shutterCallback = new ShutterCallback() { public void onShutter() { // Shutter has closed } }; private PictureCallback rawCallback = new PictureCallback() { public void onPictureTaken(byte[] _data, Camera _camera) { // TODO Handle RAW image data } }; private PictureCallback jpegCallback = new PictureCallback() { public void onPictureTaken(byte[] _data, Camera _camera) { // 設定 inJustDecodeBounds = true BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; Bitmap bitmap_def = BitmapFactory.decodeByteArray(_data, 0, _data.length, options); // 取得圖像的長寬 int width = bitmap_def.getWidth(); int height = bitmap_def.getHeight(); } }; AutoFocusCallback autoFacusCallback = new AutoFocusCallback() { @Override public void onAutoFocus(boolean focused, Camera camera) { // 當相機捉到焦點時,再啟動相機拍照 if (focused == true) { myCamera.takePicture(shutterCallback, rawCallback, jpegCallback); } } }; }
沒有留言:
張貼留言