Подтвердить что ты не робот

SurfaceView мигает черным цветом при загрузке

У меня есть приложение для рисования, которое занимает около 2-5 секунд для загрузки чертежа для сложных рисунков (выполняется через AsyncTask). Для лучшего удобства пользователей за это время я запустил сохраненную версию PNG рисунка, который у меня есть из каталога приложения, как ImageView, и покажите загрузку ProgressBar вызов setContentView() в конструкторе Activity:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
    android:id="@+id/flash"
    android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@color/note_bg_white"
        android:contentDescription="@string/content_desc_flash_img"
        android:focusable="false" />
<RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="6dp"
        android:paddingLeft="6dp"
    android:paddingRight="6dp"
        android:gravity="bottom|center_vertical">
        <ProgressBar 
            style="?android:attr/progressBarStyleHorizontal"
    android:id="@+id/toolbar_progress"
    android:layout_width="match_parent"
    android:layout_height="18dp"
    android:gravity="bottom|center_vertical" />
    </RelativeLayout>
</FrameLayout>

Когда значение AsyncTask завершено, я снова вызываю setContentView() с новым макетом:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffff">
    <com.my.package.DrawingCanvas
        android:id="@+id/canvas"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:focusable="true"
        android:background="#ffffff" />
</RelativeLayout>

Когда я использовал простую модель Canvas, это сработало отлично, так как пользовательский DrawingCanvas View рисовал чертеж на экране на начальном onDraw() перед его показом пользователю, но теперь используя SurfaceView с контуром рисования, я вижу мигающий макет, затем, когда рисунок загружен, черный экран около секунды, а затем, наконец, новый DrawingCanvas.

Я предполагаю, что причина связана с временем запуска потока цикла чертежа, и я оставил свой верх над onDraw() в SurfaceView, и он вызван, но холст, доступный в onDraw(), похоже, не обращается к SurfaceView. Я также попытался установить сплошной цвет фона в XML выше, надеясь, как минимум, на белый фон, но они никогда не влияют, даже устанавливая его из кода.

Любые советы или объяснения того, что я вижу на черном экране?

EDIT:

Хорошо, подтвердили, что onDraw() рисует на один и тот же холст, поэтому оставил мои схемы рисования там, надеясь, что при первоначальном показе SurfaceView пользователь увидит эти рисунки, как в обычной реализации Canvas, и когда рисовальная нить развернулась, она перезапишет Canvas.

Однако, если я очищаю операции потока чертежа, я вижу результаты onDraw(), но снова, ПОСЛЕ ЧЕРНОЙ ФУНКЦИИ. И если я полностью удалю переопределение onDraw(), я все еще вижу черную вспышку, а затем вижу макет с белым фоном из XML.

Итак, похоже, что бы я ни был, я всегда увижу черный экран, если, возможно, вместо переключения макетов я просто изменяю существующий макет flash, который уже активен?

EDIT2:

Попробовали использовать ViewStub, чтобы я мог надуть SurfaceView в существующий вид после загрузки заметки, но тот же самый применяется. Насколько я могу судить, существует значительная (~ 200 мс) задержка между конструктором SurfaceView и вызовом функции surfaceCreated(), но не уверен, что это то, где происходит черный экран, или почему экран рисуется черный...

EDIT3:

Моя последняя попытка теперь включает в себя создание SurfaceView прозрачного. Это в сочетании с оставлением существующего макета на месте и просто добавлением к этому макету через ViewStub привело бы к созданию рабочего решения, хотя, тем не менее, но в течение секунды секунды, когда SurfaceView загружается, экран мигает черным цветом до отображения SurfaceView, как прозрачный. Если у кого есть какие-то другие идеи, пожалуйста, разместите их.

4b9b3361

Ответ 1

Думаю, я нашел причину черной вспышки. В моем случае я использую SurfaceView внутри фрагмента и динамически добавляю этот фрагмент к активности после некоторых действий. В тот момент, когда я добавляю фрагмент к активности, экран мигает черным. Я проверил grepcode для источника SurfaceView, и вот что я нашел: когда поверхностный вид появляется в окне в самое первое время, он запрашивает изменение параметров окна, вызывая частный метод IWindowSession.relayout(..). Этот метод "дает" вам новый кадр, окно и поверхность окна. Я думаю, что в этот момент экран мигает.

Решение довольно просто: если у вашего окна уже есть соответствующие параметры, он не обновит все материалы окна, и экран не будет мигать. Самое простое решение состоит в том, чтобы добавить поверхностный SurfaceView высотой 0px к первому расположению вашей деятельности. Это позволит воссоздать окно до того, как действие будет показано на экране, а когда вы установите второй макет, он просто продолжит использование окна с текущими параметрами. Надеюсь, это поможет.

ОБНОВЛЕНИЕ: Похоже, что после многих лет это поведение по-прежнему существует. Я рекомендую использовать TextureView вместо SurfaceView. Это буквально новая реализация той же вещи, которая не имеет этого побочного эффекта, а также не имеет проблемы с черным фоном при ее перемещении (например, в ScrollView, ViewPager, RecyclerView и т.д.).

Ответ 2

Я бы не сделал этого с двумя отдельными макетами.

Попробуйте сделать свой корневой элемент RelativeLayout, а затем иметь SurfaceView и ImageView, чтобы они были дочерними. Что бы ни случилось с вашими потоками и т.д., ImageView должен быть полностью непрозрачным поверх SurfaceView, поэтому вы не получите вспышку.

Как только ваш рабочий поток загрузил чертеж, и SurfaceView может нарисовать себя, удалите индикатор выполнения и ImageView из иерархии представлений.

Ответ 3

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

Ответ 4

Вам нужно убедиться, что onSurfaceChanged() не возвращается, пока вы полностью не нарисовали и не разместили содержимое SurfaceView Surface.

Ответ 5

Если вы используете NavigationDrawer с фрагментами, то решение Evos не будет работать!
Попробуйте использовать NavigationDrawer с активностями вместо фрагментов, это поможет вам на 100%

Как реализовать NavDrawer с действиями: ссылка
Еще одна полезная ссылка . (в случае, если SurfaceView будет рисовать поверх SlidingMenu)

Ответ 6

"холст, доступный в onDraw(), похоже, не обращается к SurfaceView" - Вы уверены, что не создаете второй (или третий...) экземпляр Surface View? И некоторые из них могут быть черными и отображаться на секунду. Я не вижу код здесь, поэтому, я не могу сказать точно, но если бы это было в моем приложении, я бы сначала проверил эту ошибку.

Ответ 7

Я столкнулся с той же проблемой, но благодарю за этот ответ

Существует менее беспорядочный подход, просто. GetWindow() SetFormat (PixelFormat.TRANSLUCENT); в деятельности хозяина onCreate() перед вызовом setContentView().

Ответ 8

Решение CrazyOrr работало для меня, но оно было глубоко в комментариях к верхнему ответу Evos, так что вот оно снова:

Существует менее беспорядочный подход, просто. GetWindow() SetFormat (PixelFormat.TRANSLUCENT); в деятельности хозяина onCreate() перед вызовом setContentView(). - CrazyOrr 5 мая '16 в 7:29

Проще говоря,

getWindow().setFormat(PixelFormat.TRANSLUCENT); 

в действии onCreate() работал у меня.