SurfaceView在加载时闪烁黑色
我有一个绘图应用程序需要大约2-5秒来加载绘图复杂的图纸(通过一个AsyncTask
完成)。 为了获得更好的用户体验,在此期间,我将存储的PNG版本的graphics从应用程序目录中作为ImageView
刷新,并在Activity构造函数中显示调用setContentView()
的加载ProgressBar
:
<?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。
我假设原因与绘制循环线程的启动时间有关,并且我已经在SurfaceView
留下了onDraw()
覆盖,并且它被调用,但是onDraw()
中的可用canvas没有似乎画到SurfaceView
。 我也尝试在上面的XML中设置一个纯色背景,希望至less显示一个白色背景,但是这些从来没有影响,甚至从代码设置。
任何build议或解释我所看到的黑屏?
编辑:
好的,已经确认onDraw()正在绘制到同一个canvas上,所以我的绘图操作在那里,希望在最初的SurfaceView显示中,用户可以像在常规Canvas实现中那样看到这些绘图,绘制线程已经旋转起来,它会覆盖canvas。
但是,如果我清除绘图线程操作,我会看到onDraw()结果,但是在黑屏闪烁之后再次出现。 如果我完全删除onDraw()覆盖,我仍然看到黑色闪光,然后我看到从XML的白色背景的布局。
所以,看起来不pipe怎么样,我总是会看到黑屏,除非可能不是切换布局,我只是修改已经激活的现有“闪光灯”布局?
EDIT2:
已经尝试使用ViewStub,以便在加载注释后将SurfaceView充气到现有视图中,但仍然适用相同的issu。 就我所知,在SurfaceView构造函数和调用surfaceCreated()执行之间有一个相当大的(〜200ms)的延迟,但不知道这是黑屏发生的地方,还是为什么屏幕被绘制到黑色…
EDIT3:
现在我最后的尝试包括使SurfaceView透明 。 这与现有的布局相结合,并简单地通过ViewStub添加到该布局将产生一个工作的解决scheme,我虽然,但仍然,当SurfaceView加载屏幕闪烁黑屏之前SurfaceView显示,如透明。 如果有人有任何其他的想法尝试,请张贴他们。
我想我find了黑闪的原因。 在我的情况下,我在片段中使用SurfaceView,并在执行一些操作后dynamic地将这个片段添加到活动中。 当我将片段添加到活动时,屏幕闪烁黑色。 我检查出了SurfaceView源代码的grepcode,下面是我发现的:当表面视图出现在窗口中时,它通过调用私有的IWindowSession.relayout(..)
方法来请求窗口的参数更改。 这种方法“给”你一个新的框架,窗口和窗口表面。 我觉得那个时候屏幕正在闪烁。
解决方法非常简单:如果你的窗口已经有了合适的参数,它将不会刷新所有窗口的东西,屏幕也不会闪烁。 最简单的解决scheme是在您的活动的第一个布局中添加一个0px
高度的普通SurfaceView。 这将在屏幕上显示活动之前重新创build窗口,当您设置第二个布局时,它将继续使用具有当前参数的窗口。 我希望这有帮助。
更新 :看起来像多年后这种行为仍然存在。 我会build议使用TextureView而不是SurfaceView。 这实际上是一个新的实现相同的东西,没有这个副作用,以及没有黑色背景的问题,当你移动它(例如在ScrollView,ViewPager,RecyclerView等)。
我不会用两个单独的布局来做到这一点。
尝试使你的根元素为RelativeLayout,然后让SurfaceView和ImageView成为兄弟姐妹。 不pipe你的线程发生什么事情,ImageView都应该被绘制在SurfaceView的顶端,所以你不会得到一个Flash。
一旦您的工作线程加载了绘图,并且SurfaceView可以绘制自己,请从视图层次结构中删除进度条和ImageView。
我假设你在表面视图中绘制了一些沉重的代码,因为据我所知,表面视图将在绘制所有内容后显示完整的视图。 我build议你先去表面视图的onDraw()方法,然后在canvas的背景上设置然后强制无效以避免黑屏。 添加一个条件,以确保这个强制无效只被调用一次。
您需要确保onSurfaceChanged()不会返回,直到完全绘制并发布SurfaceView的Surface的内容为止。
如果您使用带有片段的NavigationDrawer,那么Evos解决scheme将无法工作!
尝试使用具有活动而不是片段的NavigationDrawer,这将帮助你100%
如何使用活动: 链接来实现NavDrawer
另一个有用的链接 (如果SurfaceView将绘制在SlidingMenu的顶部)
“onDraw()中可用的canvas似乎没有绘制到SurfaceView” – 您确定没有创buildSurface View的第二个(或第三个)实例吗? 而其中一些可能是黑色的,会显示一秒钟。 我没有在这里看到代码,所以,我不能确定地说,但如果它在我的应用程序,我会首先检查这个错误。
我面临同样的问题,但感谢这个答案
有一个不太混乱的方法,只需把getWindow()。setFormat(PixelFormat.TRANSLUCENT); 在调用setContentView()之前,在主机活动的onCreate()callback中。
CrazyOrr的解决scheme为我工作,但在Evos的最佳答案的评论深刻,所以这里又是:
有一个不太混乱的方法,只需把getWindow()。setFormat(PixelFormat.TRANSLUCENT); 在调用setContentView()之前,在主机活动的onCreate()callback中。 – CrazyOrr 5月16日在7:29
简单地说
getWindow().setFormat(PixelFormat.TRANSLUCENT);
在activity的onCreate()
为我工作。