2012-01-07 5 views
31

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

<?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 бы нарисовать рисунок на осыпь n на начальном onDraw() перед его показом пользователю, но теперь используя SurfaceView с контуром рисования, я вижу свернутый макет, затем, когда загружается чертеж, черный экран около секунды, а затем, наконец, новый DrawingCanvas.

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

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

EDIT:

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

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

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

EDIT2:

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

EDIT3:

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

+0

Некоторые тяжелые операции в onCreate могут дать такие результаты. – Ronnie

+0

Я показываю макет 'flash' в onCreate(), без задержки. Задержка/черный экран появляется после загрузки чертежа, и я запускаю SurfaceView, который включает только начальный поток. –

+0

Можем ли мы увидеть источник вашего класса DrawingCanvas? –

ответ

0

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

4

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

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

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

+0

Я пробовал это без успеха, но могу вскоре вернуться к нему, если не могу найти основную причину вспышки. –

+0

Должен работать. Может быть, это поможет, если вы разместите код для com.my.package.DrawingCanvas? –

+0

Это не объясняет проблему, но, похоже, работает как обходной путь, поэтому награда присуждается, поскольку hackbod никогда не расширился, что может быть основной причиной, и все, что я пробовал, связанное с этой линией мышления, кажется, терпит неудачу. –

1

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

+0

Как обеспечить, чтобы Surfaceview полностью рисовался и отправлялся? Что может вызвать вызов 'onSurfaceChanged()' до полной записи и рисования? Я подтвердил, что View вызывает onSurfaceChanged() после начала моего потока чертежей, но до того, как цикл рисования сможет завершить его первую операцию (вызван при вызове lockCanvas()?) –

+0

hackbod является старшим разработчиком команда Android, она, вероятно, прав. Мне никогда не приходило в голову пытаться рисовать из onSurfaceChanged(), но это очевидно, теперь она предлагает это. Она означает, что в вашем onSurfaceChanged() вы вызываете holder.lockCanvas(), затем рисуете что-то, затем вызываете holder.unlockCanvasAndPost(). Если у вас есть изображение с образцом-заполнителем и в дереве просмотра, просто заполнение холста surfaceview с полной прозрачностью должно обеспечить желаемый эффект (не затенять его). –

+0

Добавление кода чертежа в 'onSurfaceChanged()' ничего не сделало, к сожалению, все еще видя черную вспышку. –

2

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

142

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

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

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

+15

Как сумасшедший, как звучит этот ответ, добавление 0px * 0px SurfaceView в макете вашей активности (активность корневого макета) фактически удаляет черное мигание SurfaceView в вашем фрагменте! Я сделал это, и он отлично работает! –

+0

@ErikZ: спасибо, пустой SurfaceView решил мою проблему! – Oliver

+0

Это решение удалило некоторые тяжелые мерцания из [CameraPreview, как описано в документации] (http://developer.android.com/guide/topics/media/camera.html#camera-preview) - особенно при запуске предварительного просмотра. – miracula

1

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

Как реализовать NavDrawer с деятельностью: link
Другим полезным link.(В случае SurfaceView будет опираться на вершине SlidingMenu)

+0

Ну, это даже не связано с навигационным ящиком, это больше о динамически добавленном фрагменте с поверхностью внутри. – Evos

0

Я сталкиваюсь с теми же проблемами, но спасибо за этот ответ

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

0

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

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

Просто положить

getWindow().setFormat(PixelFormat.TRANSLUCENT); 

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

Смежные вопросы