问题 使用带闪存的webview时屏幕闪烁


编辑:我做了一个演示apk,所以你可以理解我的意思: http://cl.ly/3g0s1p030j243y0p3m2F

对于我的应用程序,我想要一个“超级Power Point”,或者一个主题演讲(商业团队将向他们的客户展示产品)使用Android平板电脑上的所有Android优点,手势等。由于Honeycomb还没有准备就绪,因为我们在3月之前需要它,我们选择了一些随机的Froyo平板电脑(Archos 101),但我的问题是我试过的每一款平板电脑/手机。

我做了一个非常棒的应用程序,但对于演示期间的一些动画,客户想要使用flash动画。因为我无法在Android中轻松编写动画(类似小电影/动画图形)并且缺乏时间,这似乎是一个好主意。

所以,经过网上搜索后,我使用了webview和这段代码:

    WebView mWebView1 = (WebView) findViewById(R.id.webview1);
    mWebView1.getSettings().setJavaScriptEnabled(true);
    mWebView1.getSettings().setPluginsEnabled(true);
    mWebView1.loadUrl("file:///android_asset/graph_01.swf");

这项工作相当不错,但在我试过的每台设备上(Archos 101,Nexus One,Nexus S,Galaxy S,Xperia,Desire,HTC Hero,以及更多)每次活动都有一个webview闪烁,几毫秒的黑屏,然后动画终于出现了。

PS:我的布局也很简单:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<WebView android:id="@+id/webview1" android:layout_height="fill_parent"
            android:layout_width="fill_parent"></WebView>
</LinearLayout>

请帮助我,我无法想象我是唯一一个面对这个问题的人。

非常感谢任何帮助。你有我的所有代码和演示apk。


5716
2018-02-23 19:26


起源

我在Android浏览器上注意到了这种行为......我担心你可能需要等待很长时间才能修复它... - Kevin Gaudin
@ Profete162你可以分享你的项目文件吗... - Jayson Tamayo


答案:


此答案后来添加:

所以问题是Adobe的Flash Player创建了一个 SurfaceView 在 - 的里面 WebView 并且之间存在延迟 SurfaceView 出现和Flash引擎困扰绘制任何东西。在那个小间隙中,SurfaceView看起来完全是黑色的。

我发现的解决方案是将WebView子类化并将自定义的SurfaceView添加到视图树中。其次,禁止对Adobe视图的第一次draw()调用也很重要。我的子类WebView的代码如下:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.webkit.WebView;
import android.widget.AbsoluteLayout;

public class FixAdobeWebView extends WebView {

    View whiteView;
    private boolean eatenFirstFlashDraw;

    public FixAdobeWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
        whiteView = new WhiteSurfaceView(context);
        whiteView.setLayoutParams(new AbsoluteLayout.LayoutParams(800, 480, 0, 0));
        addView(whiteView);
    }


    private class WhiteSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
        public WhiteSurfaceView(Context context) {
            super(context);
            getHolder().addCallback(this);
        }
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            Canvas canvas = holder.lockCanvas();
            if (canvas != null) {
                canvas.drawColor(Color.WHITE);
                holder.unlockCanvasAndPost(canvas);
            }
        }
        @Override
        public void surfaceCreated(SurfaceHolder holder) { }
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) { }
    }


    //
    // Override drawChild to eat the first draw of the FlashPaintSurface
    //
    @Override 
    protected boolean drawChild (Canvas canvas, View child, long drawingTime) {
             if (!eatenFirstFlashDraw && child.getClass().getName().equals("com.adobe.flashplayer.FlashPaintSurface")) {
                 eatenFirstFlashDraw = true;
                 return true;
             }
        return super.drawChild(canvas, child, drawingTime);
    }
}

布局XML应声明此类的实例,即:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@android:color/white"
    >
<org.test.FixAdobeWebView android:id="@+id/webview1" 
    android:layout_height="fill_parent"
    android:layout_width="fill_parent"
    />
</LinearLayout>

在我的运行CM6.1的Nexus One上,这完全可以工作,因为在Flash SurfaceView开始绘图之前,WebView显示为纯白色。您可能需要稍微调整一下,例如摆脱硬编码的800x480尺寸,并且一旦不再需要就破坏白色SurfaceView。

原文(错误)答案:

看起来Adobe应该归咎于这个。

到目前为止,我发现的最不可靠的解决方法是:

  1. 使WebView的父级背景为兼容颜色(即白色)。
  2. 最初隐藏WebView。
  3. 等到你得到页面加载的事件,然后排队一个runnable以在一秒钟的延迟后显示WebView。

这意味着你可以在看到任何东西之前得到一个保证一秒钟的延迟,但它不会像那个可怕的黑色闪光一样震撼。

布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@android:color/white"
    >
<WebView android:id="@+id/webview1" 
    android:layout_height="fill_parent"
    android:layout_width="fill_parent"
    android:visibility="invisible"    
    />
</LinearLayout>

码:

    final Handler handler = new Handler();
    ...
    final WebView mWebView1 = (WebView) findViewById(R.id.webview1);
    mWebView1.getSettings().setJavaScriptEnabled(true);
    mWebView1.getSettings().setPluginsEnabled(true);
    mWebView1.setWebViewClient(new WebViewClient() {
        @Override 
        public void onPageFinished(WebView view, String url) {
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mWebView1.setVisibility(View.VISIBLE);                      
                }
            }, 1000);
        }
    });
    mWebView1.loadUrl("file:///android_asset/graph_01.swf");        

可能有更好的方法可以消除固定延迟的需要......

自从我用Flash做了一些事情已经有一段时间了,但我似乎还记得Flash控件有一种方法可以使用浏览器的Javascript引擎(一个快速的Google出现了 Flex Ajax Bridge 这似乎很可能)。

您可以做的是,使用上述桥接器,使用ActionScript调用一个执行alert()的Javascript函数。在您的Java代码中,您将mWebView1挂钩到 WebChromeClient 实现 onJsAlert()。在该功能中,您可以使WebView可见。


13
2018-02-27 20:39



刚刚试过你的代码,这似乎做了它应该做的事情(我等了一秒才看到东西)但黑色闪光灯仍然出现......我也尝试了10秒延迟,但黑色闪光灯出现在几个瞬间,而webview仍然是隐形的 - Waza_Be
诅咒,有时它确实不起作用......似乎正在创建一个SurfaceView,并且黑色闪光发生在正在创建的表面和决定绘制任何东西的Flash引擎之间。我们需要的是隐藏webview有点聪明...... - Reuben Scratton
@ Profete162我没有忘记这个问题,并计划在今天晚些时候或明天再次访问。希望给你一些好消息,但没有承诺。 - Reuben Scratton
你好Reuben,我接受了你的回答并投票给了你我所承诺的所有赏金。不幸的是,这个问题没有得到解决,正如我先说的那样。非常感谢你的帮助,即使我对修复有强烈的悲观态度,我也会保持双手交叉。 - Waza_Be
@ Profete162。我做到了!我很快就会更新我的答案......简而言之,你需要在Flash之上粘贴另一个SurfaceView ...... - Reuben Scratton