TextureView выдает фатальный сигнал 11 после возобновления работы приложения

У меня есть TextureView, основанный на примере Romain Guy, который можно найти здесь. На Android 4.3 и 4.4 после нескольких циклов приостановки и возобновления работы приложения происходит сбой приложения, и единственным признаком ошибки является фатальный сигнал 11 в LogCat. Я создал тестовое приложение, которое использует точный код Ромена Гая, чтобы проверить, было ли это что-то, что я сделал в своем коде, и код Ромена также дает сбой с фатальным сигналом 11.

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

Я также определил, что сбой происходит во время вызова canvas.drawX (drawColor, drawBitmap, drawRect и т. д.). Блокировка и разблокировка холста, похоже, не проблема. Я подозреваю, что поток отменяется, в то время как какой-то другой код все еще использует холст, но мне очень трудно отслеживать проблему из-за отсутствия каких-либо реальных исключений и довольно непоследовательного сбоя.

Мы будем очень признательны за любые идеи.


person Kaleb    schedule 20.12.2013    source источник


Ответы (3)


Когда TextureView теряет видимость (либо из-за поворота экрана, либо из-за того, что другие Activity выходят на передний план, либо вы нажимаете кнопку «Домой»), он аннулирует свой SurfaceTexture.OnFrameAvailableListenerGrepCode< /а>). Похоже, когда это происходит, и в этот самый момент экземпляр Canvas выполняет drawX() методов изначально в коде C++, приложение падает, потому что по какой-то причине память, содержащая этот холст, очищается до завершения метода. Однако, поскольку методы Canvas.drawX() используют собственный код C++ для Android, C++ не выдает NullPointerException (Как поймать исключение нулевого указателя?) и, следовательно, система обработки исключений Java в этом случае бесполезна.

Эта проблема делает непригодным для использования класс TextureView, если вы вызываете методы drawX() более чем несколько раз или рисуете какие-то сложные вещи в Canvas.

Очень похоже на ошибку в многопоточности и/или на стороне кода C++. Я открыл проблему с сообщением об этом: https://code.google.com/p/android/issues/detail?id=85380.

EDIT: я нашел надежный способ избежать вызова методов drawX(), когда TextureView больше не виден и, следовательно, приложение начинает падать: прервите поток, рисующий Canvas, и проверяйте перед каждым вызов любого метода drawX(), который прерывает поток. Предыдущие методы onPause() называются методами drawX(), не вызовут ошибок.

mThread = new Thread() {
    @Override
    public void run() {
        Canvas canvas = mTV.lockCanvas();

        /** Draw your stuff on the canvas but check before every
            single drawX() call whether mThread has been interrupted **/
        Paint p = new Paint();
        p.setColor(Color.RED);
        for (int n=0; n<5000; ++n) {
            if (mThread.isInterrupted())
                break;
            canvas.drawCircle(0, 0, 300, p);
        }
        /** **/

        mTV.unlockCanvasAndPost(canvas);
    };
mThread.start();

А затем на onPause() — буквально за мгновение до того, как вызов Canvas.drawX() начнёт крашить приложение — прерываем поток:

@Override
public void onPause() {
    super.onPause();
    if (mThread != null) {
        mThread.interrupt();
        mThread = null;
    }
}

Добавьте также тот же самый код к onStop() и к onDestroy(). Я также пытался использовать метод TextureView.onVisibilityChanged(), переопределяя его для прерывания потока. Но этот метод вызывается почти через 500 мс после вызова onPause(), когда уже слишком поздно и вызовы drawX() начинают вызывать сбой приложения.

person AxeEffect    schedule 19.12.2014
comment
остановка и предотвращение вызовов отрисовки в onPause действительно сработала для меня! хорошее временное решение этой странной ошибки. надеюсь скоро исправят. - person doomsdaymachine; 06.06.2015
comment
Разве вы не можете просто Thread.join() добавить поток рендерера в onPause()? Это должно гарантировать, что он прекратил выполнение до того, как TextureView начнет очищать материал. interrupt() не синхронен; он просто устанавливает флаг и выкидывает другой поток из wait(). Если поток рендерера продолжает выполняться после возврата onPause(), это ошибка приложения, а не проблема фреймворка. - person fadden; 19.06.2015

У меня была аналогичная проблема, и оказалось, что это тривиальное исключение NullPointerException в моем коде, которое каким-то образом вызвало ошибку сегментации (сигнал 11) всего процесса. По-видимому, исключения внутри обратных вызовов SurfaceTextureListener.onSurfaceTextureAvailable() обрабатываются неправильно. Вероятно, это какая-то проблема JNI.

В качестве грязного обходного пути вы можете поймать все исключения из SurfaceTextureListener с помощью

try {
} catch (Throwable t) {
    //do some tear down - better than signal 11
}

Я решил не сообщать об ошибке Android, поскольку я не могу воспроизвести ее на 4.4.2, поэтому, вероятно, ее исправили.

person Iwo Banas    schedule 04.04.2014
comment
Я вернулся к этому сегодня и могу подтвердить, что проблема все еще существует в 4.4.4, хотя кажется, что ее сложнее воспроизвести. Я поместил операторы try/catch вокруг каждого вызова метода, который я делаю, но я все еще не могу поймать ошибку. Моя ошибка SIGSEGV = ошибка сегментации в собственном коде, что, вероятно, объясняет, почему исключения не выдаются. - person Kaleb; 10.07.2014

if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

person Hemang    schedule 10.07.2014
comment
Это, к сожалению, не решило проблему. - person Kaleb; 10.07.2014
comment
Этот ответ был бы гораздо полезнее с объяснением того, чего он пытался достичь и почему это помогло. Мое лучшее предположение состоит в том, что это изменит шансы на попадание в состояние гонки, что на самом деле не решает проблему. - person fadden; 19.06.2015
comment
это совершенно не относится к делу - person Yevgen Kulik; 22.02.2017