SurfaceView мигает черным при загрузке - PullRequest
32 голосов
/ 08 января 2012

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

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

РЕДАКТИРОВАТЬ:

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

Однако, если я очищаю операции потока рисунка, я вижу результаты onDraw (), но снова, ПОСЛЕ черного экрана.И если я полностью удаляю переопределение onDraw (), я все еще вижу черную вспышку, а затем я вижу макет с белым фоном из XML.

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

EDIT2:

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

EDIT3:

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

Ответы [ 8 ]

147 голосов
/ 28 сентября 2012

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

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

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

5 голосов
/ 16 января 2012

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

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

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

2 голосов
/ 17 января 2012

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

1 голос
/ 07 ноября 2014

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

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

1 голос
/ 17 января 2012

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

0 голосов
/ 06 июня 2017

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

Есть менее грязный подход, просто поместите getWindow ().setFormat (PixelFormat.TRANSLUCENT);в обратном вызове onCreate () активности хоста перед вызовом setContentView ().- CrazyOrr 5 мая 16 года в 7:29

Простое помещение

getWindow().setFormat(PixelFormat.TRANSLUCENT); 

в onCreate() задания помогло мне.

0 голосов
/ 26 мая 2017

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

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

0 голосов
/ 15 января 2012

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

...