안녕하세요 이제 막안드로이드 개발을 시작한 초보 입니다.
현재 앱을 하나 만들고 있는데 카메라 사진촬영후 프리뷰 만드는 과정에서 메모리 누수현상이 발생하여 앱이 종료됩니다.
메모리 누수현상이 발생하는 순서는 아래와 같습니다.
1. 사진촬영
2. 사진저장
3. 사진활영
4. App종료
아래는 오류 내용입니다.
Process: com.example.issue_camera9, PID: 18610
java.lang.OutOfMemoryError
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:928)
at android.graphics.Bitmap.createBitmap(Bitmap.java:901)
at android.graphics.Bitmap.createBitmap(Bitmap.java:833)
at com.example.issue_camera9.SurfaceCamera.Preview$2.onPictureTaken(Preview.java:299)
at android.hardware.Camera$EventHandler.handleMessage(Camera.java:987)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5602)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
at dalvik.system.NativeStart.main(Native Method)
Previw.java
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(TAG, "surfaceDestroyed1");
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
Log.d(TAG, "surfaceDestroyed");
}
}
위부분은 카메라에서 나가면 카메라를 종료시키는 부분입니다.
public void PressTakePicture() {
if (mIsTakingPhoto) {
return;
}
mCamera.startPreview();
Camera.PictureCallback jpegPictureCallback = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
int maxSize = 2048;
mCamera.stopPreview();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(data, 0, data.length, options);
int width = options.outWidth;
int height = options.outHeight;
int srcSize = Math.max(width, height);
options.inSampleSize = maxSize < srcSize ? (srcSize / maxSize) : 1;
options.inJustDecodeBounds = false;
Bitmap tmp = BitmapFactory.decodeByteArray(data, 0, data.length, options);
int size = Math.min(options.outWidth, options.outHeight);
float previewRatio = (float) mSurfaceSize.height / (float) mSurfaceSize.width;
float cameraRatio = (float) options.outHeight / (float) options.outWidth;
Matrix matrix = new Matrix();
matrix.postRotate(90);
int length = (int) (size * (previewRatio / cameraRatio));
int rid = size - length;
Bitmap source = Bitmap.createBitmap(tmp,
0, // x
(int) (rid * 0.5), // y
length,
length,
matrix, true);
tmp.recycle();
Log.d(TAG, "PressTakePicture (int) (rid * 0.5) : " + (int) (rid * 0.5));
Log.d(TAG, "PressTakePicture length : " + length);
Log.d(TAG, "PressTakePicture matrix : " + matrix);
BusHolder.getInstance().post(new TakePicture(source));
mIsTakingPhoto = false;
}
};
Camera.ShutterCallback shutterCallback = new Camera.ShutterCallback() {
@Override
public void onShutter() {
}
};
try {
mCamera.takePicture(shutterCallback, null, jpegPictureCallback);
mIsTakingPhoto = true;
} catch (Exception e) {
e.printStackTrace();
}
}
최초로 비트맵 이미지를 만는 곳입니다.
MainActivity.java
Button.OnClickListener mClickListener = new View.OnClickListener() {
public void onClick(View v) {
switch (v.getId()) {
case R.id.picture_save_button:
mCurrentMode = MODE_CAMERA_PREVIEW;
mSquaredView.setImageBitmap(null);
SaveBitmapToFile();
mPreview.retake();
findViewById(R.id.picture_save_button).setVisibility(View.GONE);
break;
}
}
};
private void SaveBitmapToFile() {
File picFile = getOutputMediaFile();
try {
FileOutputStream fos = new FileOutputStream(picFile);
if (mBitmap != null) {
mBitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos);
}
fos.close();
if (mBitmap != null) {
mBitmap.recycle();
Log.d(TAG, "recycle");
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private File getOutputMediaFile() {
File mediaStorageDir = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),
"issue_camera9"
);
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.d(TAG, "failed to create directory");
return null;
}
}
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
Log.d(TAG, "getOutputMediaFile : "+mediaStorageDir.getPath() + File.separator
+ JPEG_FILE_PREFIX + timeStamp + JPEG_FILE_SUFFIX);
mediaFile = new File(
mediaStorageDir.getPath() + File.separator
+ JPEG_FILE_PREFIX + timeStamp + JPEG_FILE_SUFFIX
);
return mediaFile;
}
위부분은 사진촬영후 사진저장버튼을 누르면 이미지파일을 저장하는 코드입니다.
여기까지 읽어주셔서 감사합니다.