SurfaceView在加载时闪烁黑色

Pau*_*ega 32 android surfaceview android-canvas

我有一个绘图应用程序需要大约2-5秒来加载复杂图纸的绘图(通过一个完成AsyncTask).为了获得更好的用户体验,在此期间我将应用程序目录中存储的PNG版本作为一个闪存ImageView,并在Activity构造函数中显示加载ProgressBar调用setContentView():

<?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>
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

当我使用一个简单的Canvas模型时,这非常有效,因为自定义DrawingCanvas ViewonDraw()在向用户显示之前将绘图绘制到初始屏幕上,但现在使用SurfaceView带有绘图循环,我看到闪烁的布局,然后加载图形时,黑屏大约一秒钟,最后是新的DrawingCanvas.

我假设原因与绘制循环线程的启动时间有关,并且我已经离开了我onDraw()的内部SurfaceView,并且它被调用,但是可用的画布onDraw()似乎没有绘制到SurfaceView.我也尝试在XML中设置纯色背景,希望至少能够显示白色背景,但这些背景似乎永远不会生效,甚至从代码设置它.

我对黑屏的看法有什么建议或解释吗?

编辑:

好的,已经确认onDraw()正在绘制到同一个画布,所以在那里留下我的绘制操作以及希望在初始显示SurfaceView时,用户会看到像常规Canvas实现中的那些绘图,以及绘制线程已经旋转,它将覆盖Canvas.

但是,如果我清除了绘图线程的操作,我确实看到了onDraw()的结果,但是再次,黑屏闪烁之后.如果我完全删除onDraw()覆盖,我仍然会看到黑色闪光,然后我看到XML中带有白色背景的布局.

所以,看起来无论如何,我总是会看到黑屏,除非可能不是切换布局,我只是修改已经激活的现有"闪存"布局?

EDIT2:

尝试过使用ViewStub,这样我可以在加载音符后将SurfaceView充气到现有的View中,但同样的issu仍然适用.就像我所知,SurfaceView构造函数和对surfaceCreated()执行的调用之间有一个相当大的(约200ms)延迟,但不确定这是黑屏发生的原因,或者为什么屏幕被绘制到黑色...

EDIT3:

我现在的最后一次尝试包括使SurfaceView透明化.这与现有的布局相结合,只需通过ViewStub添加到该布局就可以得到一个可行的解决方案,但是,当SurfaceView加载时,在SurfaceView显示之前,屏幕闪烁黑色,透明的.如果有人有任何其他想法尝试,请发布它们.

Evo*_*vos 147

我想我找到了黑色闪光的原因.在我的情况下,我在Fragment中使用SurfaceView,并在执行某些操作后动态地将此片段添加到活动中.当我将片段添加到活动时,屏幕闪烁黑色.我检查了SurfaceView源代码的grepcode,这就是我发现的:当窗口中的表面视图出现时,它会通过调用私有IWindowSession.relayout(..)方法来请求窗口的参数发生变化.此方法"为您提供"新的框架,窗口和窗口表面.我觉得那一刻屏幕正好闪烁.

解决方案非常简单:如果您的窗口已经有适当的参数,它将不会刷新所有窗口的东西,屏幕也不会闪烁.最简单的解决方案是将0px高度平面SurfaceView 添加到活动的第一个布局中.这将在屏幕上显示活动之前重新创建窗口,当您设置第二个布局时,它将继续使用具有当前参数的窗口.我希望这有帮助.

更新:看起来多年后这种行为仍然存在.我建议使用TextureView而不是SurfaceView.这实际上是一种新的实现同样的事情,没有这种副作用,以及当你(滚动型,ViewPager,RecyclerView等内例如)移动它没有黑色背景的问题.

  • 听起来很疯狂,在活动布局中添加一个0px*0px的SurfaceView(根布局的活动),实际上会删除片段中SurfaceView的黑色闪烁!我这样做了,它完美无缺! (15认同)
  • 有一种不那么混乱的方法,只需在调用setContentView()之前在主机活动的onCreate()回调中放入`getWindow().setFormat(PixelFormat.TRANSLUCENT);`. (12认同)
  • 仍在2015年工作.这完全是荒谬的解决方案. (8认同)

Reu*_*ton 5

我不会用两个单独的布局来做这个.

尝试将您的根元素设置为RelativeLayout,然后使SurfaceView和ImageView成为兄弟姐妹.无论您的线程等发生什么,ImageView都应该在SurfaceView顶部绘制完全不透明,因此您不会获得闪光.

一旦您的工作线程加载了图形并且SurfaceView可以自行绘制,请从视图层次结构中删除进度条和ImageView.


Gan*_*nus 0

“ onDraw() 中可用的画布似乎没有绘制到 SurfaceView” - 您确定不创建 Surface View 的第二个(或第三个......)实例吗?其中一些可能是黑色的并显示一秒钟。我在这里看不到代码,所以,我不能确定,但​​如果它在我的应用程序中,我会首先检查此错误。