SurfaceView 在加载时闪烁黑色 [英] SurfaceView flashes black on load

查看:30
本文介绍了SurfaceView 在加载时闪烁黑色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a drawing app that takes about 2-5 seconds to load the drawing for complicated drawings (done via an AsyncTask). For a better user experience, during this time I flash the stored PNG version of the drawing I have from the app directory as an ImageView, and show a loading ProgressBar calling setContentView() in the Activity constructor:

<?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():

When the AsyncTask is complete, I then call setContentView() again with the new layout:

<?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.

When I was using a simple Canvas model, this worked perfectly, as the custom DrawingCanvas View would draw the drawing to the screen on the initial onDraw() before being shown to the user, but now using the SurfaceView with a drawing loop, I am seeing the flashed layout, then when the drawing is loaded, a black screen for about a second, then finally the new DrawingCanvas.

我假设原因与绘图循环线程的启动时间有关,并且我在 SurfaceView 中留下了对 onDraw() 的覆盖>,它被调用,但 onDraw() 中可用的画布似乎没有绘制到 SurfaceView.我还尝试在上面的 XML 中设置纯色背景,希望至少能显示白色背景,但那些似乎从未生效,甚至从代码中设置它.

I am assuming that the reason is related to the start-up time of the drawing loop thread, and I've left my overide of onDraw() in the SurfaceView, and it gets called, but the canvas available in onDraw() does not seem to draw to the SurfaceView. I've also tried setting a solid color background in the XML above hoping at a minimum to show a white background, but those never seem to take affect, even setting it from code.

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

Any advice or an explanation of what I am seeing with the black screen?

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

Ok, have confirmed that onDraw() is drawing to the same canvas, so left my draw ops in there as well hoping that on the initial showing of the SurfaceView, the user would see those drawings like in the regular Canvas implementation, and when the drawing thread had spun up, it would overwrite the Canvas.

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

However, if I clear the drawing thread operations, I do see the onDraw() results, but again, AFTER the black screen flash. And if I remove the onDraw() override completely, I still see the black flash and then I see the layout with the white background from the XML.

所以,看起来无论如何,我总是会看到黑屏,除非我不是切换布局,而是简单地修改已经处于活动状态的现有flash"布局?

So, it looks like no matter what, I am always going to see the black screen, unless perhaps instead of switching the layouts, I simply modify the existing 'flash' layout that is already active?

编辑 2:

曾尝试使用 ViewStub 以便我可以加载笔记后将 SurfaceView 充气到现有视图中,但同样的问题仍然适用.据我所知,SurfaceView 构造函数和调用 SurfaceCreated() 执行之间存在相当大的(~200 毫秒)延迟,但不确定这是黑屏发生的地方,或者屏幕被绘制到的原因黑色...

Have tried using a ViewStub so that I can inflate the SurfaceView into the existing View after the note is loaded, but the same issu still applies. As near as I can tell, there is a sizable (~200ms) delay between the SurfaceView constructor and the call to surfaceCreated() executing, but not sure that this is where the black screen is happening, or why the screen is being drawn to black...

编辑 3:

我现在的最后尝试包括使 SurfaceView 透明.这与保留现有布局并通过 ViewStub 简单地添加到该布局相结合会产生一个有效的解决方案我虽然,但仍然,当 SurfaceView 加载时,屏幕在 SurfaceView 显示之前闪烁黑色,有一瞬间,作为透明.如果有人有任何其他想法可以尝试,请发布.

My final attempt for now includes making the SurfaceView transparent. This combined with leaving the existing layout in place and simply adding to that layout via the ViewStub would have resulted in a working solution I though, but still, for a split second when the SurfaceView is loading the screen flashes black before the SurfaceView is shown, as transparent. If anyone has any other ideas to try, please post them.

推荐答案

我想我找到了黑闪的原因.就我而言,我在 Fragment 中使用 SurfaceView,并在执行某些操作后将此片段动态添加到活动中.当我将片段添加到活动的那一刻,屏幕闪烁黑色.我检查了 SurfaceView 源代码的 grepcode,这是我发现的:当表面视图第一次出现在窗口中时,它通过调用私有 IWindowSession.relayout(..) 方法.这种方法给"你一个新的框架、窗口和窗口表面.我想屏幕就在那一刻闪烁.

I think I found the reason for the black flash. In my case I'm using a SurfaceView inside a Fragment and dynamically adding this fragment to the activity after some action. The moment when I add the fragment to the activity, the screen flashes black. I checked out grepcode for the SurfaceView source and here's what I found: when the surface view appears in the window the very fist time, it requests the window's parameters changing by calling a private IWindowSession.relayout(..) method. This method "gives" you a new frame, window, and window surface. I think the screen blinks right at that moment.

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

The solution is pretty simple: if your window already has appropriate parameters it will not refresh all the window's stuff and the screen will not blink. The simplest solution is to add a 0px height plain SurfaceView to the first layout of your activity. This will recreate the window before the activity is shown on the screen, and when you set your second layout it will just continue using the window with the current parameters. I hope this helps.

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

UPDATE: Looks like after years this behavior is still there. I would recommend to use TextureView instead of SurfaceView. This is literally a newer implementation of same thing that don't have this side effect as well as don't have a problem of black background when you moving it (for instance within ScrollView, ViewPager, RecyclerView etc).

这篇关于SurfaceView 在加载时闪烁黑色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆