在我的應用程序中,我有一個用作相機預覽的活動。我使用了一個橫跨整個屏幕的SurfaceView,以及一堆覆蓋在它上面的項目,但沒有太複雜。該活動可以啓動其他活動,然後返回到相機預覽。重新加載相機預覽之前的Android內存問題
我一直非常小心地清理資源,回收位圖,避免內存泄漏等。我可以運行這個應用程序並測試它像瘋了似的,但是當我的手機已經打開了一段時間,其他應用程序在內存,當恢復或創建保存相機預覽的活動時,我會無聲關閉。重現崩潰的常見測試用例是使用應用程序,捕捉照片(觸發處理),啓動子活動等等。退出應用程序,激發資源/圖形沉重,然後恢復我的應用程序。
這裏是在崩潰的時候有些logcat的輸出:
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
我的活動是在每一步登錄,所以這種情況發生在Activity.onCreate呼籲super.onCreate和上下文視圖設置之間我的XML佈局。我首先想到的是,獲取SurfaceHolder或SurfaceHolder方法中發生的任何事情在緊張的情況下可能會太多,但在這種情況發生之前就是這樣。它似乎是在解析我的xml佈局和構建View對象時發生在setContentView中。
我的相機預覽代碼取自我在書籍和文章中找到的示例,所以我想知道是否有任何額外的清理工作需要在surfaceDestroyed中完成?我應該嘗試在那一刻觸發垃圾回收嗎?這種想法的原因是,系統有足夠的內存讓應用程序在內存較少的情況下運行。它要麼與我自己的應用程序無法清理後本身足夠,要麼系統無法爲我的應用程序快速回收內存。我不明白的是爲什麼在setContentView期間它試圖分配這麼多新的內存。
這裏是我的面回調代碼和什麼樣的活動
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");
}
};
很高興回覆。您將從您的高級忙碌編碼指南的較舊副本中識別出SurfaceHolder.Callback。大聲笑感謝更新的獲取/發佈邏輯。我沒有8MB的東西。佈局中有一個佔位符圖像,我在頂層設計覆蓋圖(在模擬器中預覽很糟糕),但那只是大約350k。我刪除它看看是否有幫助。 – Rich 2011-03-29 20:13:19
@Rich:請記住,解壓縮後,PNG/JPG文件中的350k將會大得多,大得多。 – CommonsWare 2011-03-29 20:17:48
是的...預覽圖像是從應用程序的輸出中獲取的,所以在將其包含在佈局中之前我沒有收縮它。 1600h x 1200w x 4(argb)=將近8MB。可能一些元數據收集到8.64M?再次感謝您的幫助。 – Rich 2011-03-29 20:23:34