2011-03-29 80 views
0

在我的應用程序中,我有一個用作相機預覽的活動。我使用了一個橫跨整個屏幕的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"); 

    } 
}; 

回答

2

繼續停止預覽並釋放攝像頭onPause(),並在onResume()獲取它意譯。不管別的什麼,現在,當用戶按下HOME時,您將綁定相機並阻止其他應用程序使用它。

(順便說一句,我有這個錯誤很長一段時間,並糾正它在我的書在過去的幾個月中)

這是可能的,這將有助於你的記憶情況,但我不能肯定。如果你可以縮小什麼是要求8640000字節的分配(這真的很大),這可能會有所幫助。也許你的佈局中有一些背景圖片?

+0

很高興回覆。您將從您的高級忙碌編碼指南的較舊副本中識別出SurfaceHolder.Callback。大聲笑感謝更新的獲取/發佈邏輯。我沒有8MB的東西。佈局中有一個佔位符圖像,我在頂層設計覆蓋圖(在模擬器中預覽很糟糕),但那只是大約350k。我刪除它看看是否有幫助。 – Rich 2011-03-29 20:13:19

+0

@Rich:請記住,解壓縮後,PNG/JPG文件中的350k將會大得多,大得多。 – CommonsWare 2011-03-29 20:17:48

+0

是的...預覽圖像是從應用程序的輸出中獲取的,所以在將其包含在佈局中之前我沒有收縮它。 1600h x 1200w x 4(argb)=將近8MB。可能一些元數據收集到8.64M?再次感謝您的幫助。 – Rich 2011-03-29 20:23:34