내 앱에는 카메라 미리보기로 작동하는 활동이 있습니다. SurfaceView는 화면 전체에 걸쳐 펼쳐져 있으며, 위에 겹쳐진 여러 개의 항목이 있지만 너무 복잡하지는 않습니다. 이 활동은 다른 활동을 시작한 다음 카메라 미리보기로 다시 돌아갑니다.카메라 미리보기를 다시로드하기 전에 Android 메모리 문제가 발생했습니다.
리소스를 정리하고, 비트 맵을 재활용하고, 메모리 누수를 방지하는 등 매우 신중했습니다.이 앱을 실행하고 미친 것처럼 테스트 할 수 있지만 휴대 전화가 잠시 동안 켜져 있고 다른 앱이있는 경우 메모리를 사용하면 카메라 미리보기를 유지하는 활동을 다시 시작하거나 만들 때 자동 종료됩니다. 충돌을 재현하는 일반적인 테스트 케이스는 앱을 사용하고 스냅 사진 (처리를 트리거 함), 하위 활동을 반복해서 실행하는 것입니다. 앱에서 나와 무언가의 자원/그래픽을 비운 다음 내 앱을 다시 시작합니다. 여기
는 충돌시 몇 가지 로그 캣 출력입니다 : 내 활동은 모든 단계에서 로그인하는03-29 14:20:02.109: ERROR/dalvikvm(6368): externalAllocPossible(): footprint 2756592 + extAlloc 15831356 + n 8640000 >= max 22409232 (space for 3821284)
03-29 14:20:02.109: ERROR/dalvikvm-heap(6368): 8640000-byte external allocation too large for this process.
03-29 14:20:02.109: ERROR/dalvikvm(6368): Out of memory: Heap Size=3835KB, Allocated=2835KB, Bitmap Size=15460KB, Limit=21884KB
03-29 14:20:02.109: ERROR/dalvikvm(6368): Trim info: Footprint=5383KB, Allowed Footprint=5383KB, Trimmed=1548KB
03-29 14:20:02.109: ERROR/GraphicsJNI(6368): VM won't let us allocate 8640000 bytes
, 그래서 이것은 super.onCreate를 호출하고 상황에 맞는보기를 설정 사이에은 Activity.onCreate에서 발생 내 XML 레이아웃. 내 첫 번째 생각은 SurfaceHolder를 획득하는 과정이나 SurfaceHolder 메서드에서 발생하는 모든 작업이 타이트한 메모리 상황에서 너무 많이 일어날 수 있다는 것입니다. 그것은 내 XML 레이아웃을 구문 분석하고 뷰 개체를 구축하는 동안 setContentView에서 발생하는 것 같습니다.
내 카메라 미리보기 코드는 책과 기사에서 찾은 예제에서 가져 왔으므로 surfaceDestroyed에서 수행해야하는 추가 정리가 있는지 궁금합니다. 그 시점에서 가비지 수집을 시도해야합니까? 이 사고의 이유는 시스템에 앱이 메모리가 적은 상황에서 앱을 실행하기에 충분한 메모리가 있다는 것입니다. 그것은 내 자신의 응용 프로그램과 완전히 상관없이 정리하거나 시스템이 내 응용 프로그램을 위해 메모리를 충분히 빨리 회수 할 수 없도록해야합니다. 이해가 안되는 이유는 setContentView가 너무 많은 새 메모리를 할당하려고 시도하는 이유입니다.
여기 내 표면 콜백 코드와 미리보기를 중지하고 onPause()
에서 카메라를 분리 한 onResume()
그것을 획득 활동
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.camera_preview);
// crash occurs here
// ...other stuff
initControls();
}
private void initControls()
{
previewHolder = preview.getHolder();
previewHolder.addCallback(surfaceCallback);
previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
// ...other stuff
}
SurfaceHolder.Callback surfaceCallback = new Callback() {
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(ApplicationEx.LogTag, "surfaceDestroyed");
camera.stopPreview();
camera.release();
camera = null;
isPreviewRunning = false;
}
public void surfaceCreated(SurfaceHolder holder) {
Log.d(ApplicationEx.LogTag, "surfaceCreated");
camera = Camera.open();
try
{
camera.setPreviewDisplay(previewHolder);
}
catch(Throwable t)
{
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
Log.d(ApplicationEx.LogTag, "surfaceChanged");
if (isPreviewRunning)
{
Log.d(ApplicationEx.LogTag, "preview is running, stop preview");
camera.stopPreview();
isPreviewRunning = false;
}
Camera.Parameters parameters = camera.getParameters();
setPreviewAndPictureSize(parameters, width, height);
parameters.setPictureFormat(PixelFormat.JPEG);
parameters.setJpegQuality(85);
camera.setParameters(parameters);
camera.startPreview();
isPreviewRunning = true;
Log.d(ApplicationEx.LogTag, "end surfaceChanged");
}
};
당신이 기뻤습니다. Adv Busy Coder 's Guide의 이전 복사본에서 SurfaceHolder.Callback을 인식 할 수 있습니다. 업데이트 된 획득/릴리스 논리에 감사드립니다. 나는 거기에 8MB의 것을 아무것도 가지고 있지 않습니다. 레이아웃에 자리 표시 자 이미지가 있었는데 (에뮬레이터에서 미리보기) 위에 오버레이를 디자인했지만 바로 그게 약 350k였습니다. 나는 그것이 도움이되는지보기 위해 그것을 제거했다. – Rich
@ 리치 : PNG/JPG 파일의 350k는 일단 압축 해제되면 훨씬 더 커질 것입니다. – CommonsWare
예 ... 미리보기 이미지는 앱 출력에서 가져온 것이므로 레이아웃에 포함하기 전에 축소하지 않았습니다. 1600h x 1200w x 4 (argb) = 거의 8MB. 아마도 8.64M까지 반올림하는 메타 데이터일까요? 도움에 다시 한번 감사드립니다. – Rich