SurfaceView在加载时闪烁黑色

时间:2012-01-07 20:28:59

标签: android surfaceview android-canvas

我有一个绘图应用程序需要大约2-5秒来加载复杂图纸的绘图(通过AsyncTask完成)。为了获得更好的用户体验,在此期间,我将应用目录中存储的PNG版本作为ImageView进行了快照,并在活动中显示加载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>

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实现中的那些绘图,当绘图线程旋转时,它会覆盖画布。

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

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

EDIT2:

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

EDIT3:

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

8 个答案:

答案 0 :(得分:147)

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

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

更新:看起来好像多年后这种行为仍然存在。我建议使用TextureView而不是SurfaceView。这实际上是一个相同的新实现,没有这种副作用,并且在移动它时没有黑色背景问题(例如在ScrollView,ViewPager,RecyclerView等中)。

答案 1 :(得分:5)

我不会用两个单独的布局来做这件事。

尝试将您的根元素设为RelativeLayout,然后使SurfaceView和ImageView成为兄弟姐妹。无论你的线程等发生什么,ImageView都应该在SurfaceView上面完全不透明,所以你不会得到闪光灯。

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

答案 2 :(得分:2)

我假设您在表面视图中绘制了一些重型代码,因为据我所知,在一次绘制所有内容后,曲面视图将显示完整视图。我建议你先去表面视图的onDraw()方法,然后在画布的背景上设置,然后强制调用invalidate以避免黑屏。添加条件以确保仅强制使用此强制无效。

答案 3 :(得分:1)

在完全绘制并发布SurfaceView曲面的内容之前,您需要确保onSurfaceChanged()不会返回。

答案 4 :(得分:1)

如果您将NavigationDrawer与片段一起使用,则Evos解决方案将无效! 尝试使用NavigationDrawer与Activities而不是片段,这将帮助您100%

如何使用活动实现NavDrawer:link
另一个有用的link。 (如果SurfaceView将在SlidingMenu上绘制)

答案 5 :(得分:0)

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

答案 6 :(得分:0)

我面临同样的问题,但是感谢你的回答

  

有一个不那么混乱的方法,只是把   。getWindow()setFormat(PixelFormat.TRANSLUCENT);在主持人活动中   调用setContentView()之前的onCreate()回调。

答案 7 :(得分:0)

CrazyOrr的解决方案对我有用,但它对Evos的最佳答案的评论很深,所以这里又是:

  

有一个不那么混乱的方法,只是把   。getWindow()setFormat(PixelFormat.TRANSLUCENT);在主持人活动中   调用setContentView()之前的onCreate()回调。 - 疯狂或者5月5日   &#39; 16在7:29

简单地说

getWindow().setFormat(PixelFormat.TRANSLUCENT); 

活动onCreate()为我工作。

相关问题