重新加载相机预览之前的Android内存问题

时间:2011-03-29 18:40:50

标签: java android camera memory-management dalvik

在我的应用中,我有一个充当相机预览的活动。我在整个屏幕上使用了一个SurfaceView,以及覆盖在它上面的一堆物品,但没有太复杂。此活动可以启动其他活动,然后返回到相机预览。

我一直非常小心地清理资源,回收位图,避免内存泄漏等。我可以运行这个应用程序并疯狂地测试它,但是当我的手机已经打开一段时间而其他应用程序在内存中时,当我恢复或创建保存相机预览的Activity时,我会收到静音关闭。重现崩溃的常见测试用例是反复使用应用程序,快照照片(触发处理),启动子活动等。退出应用程序,激活一些资源/图形重,然后恢复我的应用程序。

以下是崩溃时的一些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

我的活动是记录每一步,所以这发生在调用super.onCreate和将上下文视图设置为我的xml布局之间的Activity.onCreate中。我的第一个想法是,在紧张的内存情况下,获取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");

    }
};

1 个答案:

答案 0 :(得分:2)

停止预览并在onPause()中释放相机,并在onResume()中获取。无论如何,现在,当用户按下HOME时,您将绑定相机并阻止其他应用程序使用它。

(顺便说一句,我在很长一段时间内犯了这个错误并在过去几个月里在我的书中纠正了它)

虽然我不确定,但这有可能对你的记忆情况有所帮助。如果你可以缩小究竟是什么要求8640000字节分配(这真的很大),这可能会有所帮助。也许您的布局中有一些背景图片?