Проблемы с памятью Android перед перезагрузкой предварительного просмотра камеры - PullRequest
1 голос
/ 29 марта 2011

В моем приложении у меня есть действие, которое действует как предварительный просмотр камеры.Я использую SurfaceView, растянутый по всему экрану, вместе с кучей элементов, наложенных поверх него, но ничего сложного.Это действие может запускать другие действия, которые затем возвращаются к предварительному просмотру камеры.

Я очень тщательно очищал ресурсы, перерабатывал растровые изображения, избегал утечек памяти и т. Д. Я могу запустить это приложение и проверить егокак сумасшедший, но когда мой телефон был включен некоторое время и другие приложения находятся в памяти, я получаю тихие отключения при возобновлении или создании действия, которое содержит предварительный просмотр камеры.Обычный тестовый сценарий для воспроизведения аварии - это использование приложения, создание фотографий (запускающих обработку), запуск дополнительных действий и т. Д. Снова и снова.Выйдите из приложения, запустите что-нибудь ресурсоемкое или графическое, а затем возобновите работу моего приложения.

Вот некоторые выходные данные 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, может оказаться слишком сложным в ситуации с нехваткой памяти, но это происходит гораздо раньше.Похоже, что это происходит в setContentView при анализе моего XML-макета и создании объектов View.

Код предварительного просмотра моей камеры взят из примеров, которые я нашел в книгах и статьях, поэтому мне интересно, есть лидополнительную очистку мне нужно сделать в 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 Ответ

2 голосов
/ 29 марта 2011

Остановите предварительный просмотр и отпустите камеру в onPause() и получите ее в onResume(). Независимо от всего, прямо сейчас, вы собираетесь связать камеру и запретить другим приложениям использовать ее, когда пользователь нажимает HOME.

(Кстати, я давно ошибался и исправил это в своих книгах за последние несколько месяцев)

Возможно, это поможет с вашей памятью, хотя я не уверен. Если бы вы могли сузить то, что именно запрашивает выделение 8640000 байт (что действительно очень большое), это могло бы помочь. Возможно, какое-нибудь фоновое изображение в вашем макете?

...