【问题标题】:WebView fails to render until touched Android 4.2.2 [duplicate]WebView 在触摸 Android 4.2.2 之前无法呈现 [重复]
【发布时间】:2013-02-28 04:51:45
【问题描述】:

我正在开发一款名为 Lightning Browser 的开源浏览器,但在最近更新到 Android (4.2.2) 时遇到了一些问题。

在触摸视图之前,WebViews 将无法完全呈现。它仅发生在最新的 Android 版本上。在 4.2.1 上,WebView 渲染得非常好。我使用 Nexus 7 进行开发,在收到 4.2.2 更新后,浏览器立即停止渲染。其他用户也遇到过这种情况,并且多次确认仅在 4.2.2 上发生。它正在针对 API 级别 16 和 17 发生,但我已经看到针对 API 级别 9 的 WebKit 浏览器没有这个问题。

我已尝试使用我在 Stack Overflow (Android WebView renders blank/white, view doesn't update on css changes or HTML changes, animations are choppy) 上找到的问题的解决方案来解决此问题。但是,仅将 WebView 的 RenderPriority 设置为高并不能解决它......让它在不被触摸的情况下呈现的唯一方法是将 invalidate() 命令放在 WebView 的 OnDraw() 方法中。这会导致 WebView 不断地重新绘制。这可行(有点),动画很流畅,页面加载非常快,但否则会导致 WebView 的性能下降。

我也看过这个问题(与我的非常相似),但没有很好的答案。 Android WebView Fails to Completely Render Content Until User Interaction

我所说的性能下降是指输入。文本输入滞后,WebView 本身无法像以前那样处理正在发生的事情。使用 invalidate() 方法调用对浏览器进行基准测试会使基准测试性能下降约 8%。我知道基准测试并不是万能的,但它告诉我连续绘图正在使系统紧张并导致系统忽略其他任务。

结论... Android 4.2.2 中的 WebView 在触摸之前不会呈现。我知道解决此问题的唯一方法是在 WebView 的 onDraw() 方法中调用 invalidate()。这对性能不利,我正在寻找一种不同的方法来解决这个问题。

魔法密码(我正在使用)...

class MyWebView extends WebView
{
    @Override
    onDraw(Canvas canvas)
    {
        invalidate(); 
        super.OnDraw(canvas);
    }
}

删除

invalidate();

在被触摸之前它不会渲染。

有没有人对如何使 WebView 呈现(除了我所做的)有任何建议?顺便说一句,这是我在 Stack 上提出的第一个问题,如果我不清楚或者我做错了什么,请原谅我。

编辑: 我发现这个问题here 是关于一个类似的问题,它已经解决了,问题是,我什至不明白答案是什么意思。如果有人能启发我,它可能会有所帮助。

我在 logcat 中收到此错误

E/chromium(1243): external/chromium/net/disk_cache/backend_impl.cc:2022: [0705/172030:ERROR:backend_impl.cc(2022)] Corrupt Index file

【问题讨论】:

  • 那个问题与我们的问题无关,页面是空白的,但是因为加载它有异常问题,与渲染管道无关。
  • 顺便说一句...在我的情况下,键盘/输入性能非常糟糕(并且随着页面复杂性的增加而降低),我选择在运行时使用 JQuery 触发本机输入覆盖选择 HTML 输入。它不是很优雅,但本机输入完美无缺,文本选择/剪切/粘贴并不令人沮丧......
  • 一种不会降低性能的替代方案stackoverflow.com/a/19253633/236743 :)

标签: android android-webview


【解决方案1】:

所以我终于找到了导致 WebView 不呈现的问题。我正在我的 WebView 的 WebViewClient 内启动和停止可绘制的动画。这个drawable只是一个在页面加载时旋转的刷新按钮......简单吧?

在浏览器的非全屏模式下,旋转的drawable和WebView都是同一个父级的子级,而在全屏模式下,drawable成为WebView的子级。不知何故,通过在页面加载时启动动画并在完成时(全屏)停止动画,应用程序决定旋转可绘制对象需要所有绘图能力,而 WebView 从不绘制。当处于全屏模式并且drawable成为WebView的子级时,WebView的渲染优先级高于drawable并且可以正常绘制。

这个故事的寓意是...... WebViews 喜欢成为要绘制的最高优先级的视图。如果有其他视图获得更高的优先级,它们将无法正确绘制。

我不是动画专家,所以我现在需要重新考虑如何为可绘制对象设置动画,以免中断 WebView。

希望这是有道理的。感谢阅读。

【讨论】:

  • 说到动画,我看到如果你在页面的某个地方应用一个虚拟的 HTML 动画,它会触发一个 webview 重绘......但这是一个非常肮脏的 hack......
  • 天啊。这正是我正在做的!而且我被困了很多天,为什么绘图不加载。非常感谢。所以答案是不使用旋转动画?
  • 但这不会发生在运行 Android Kitkat 的设备上。他们解决了什么问题吗?
【解决方案2】:

在清单上禁用硬件加速:

android:hardwareAccelerated="false"

【讨论】:

  • 可能不是最好的解决方案,但唯一适合我的情况。
  • 这行得通,但正如@Scarmysun 所说的那样并不可取
  • 为我工作,但我建议在本地关闭硬件加速,使用视图级别:myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);developer.android.com/guide/topics/graphics/hardware-accel
【解决方案3】:

请查看@Olivier 在Android WebView renders blank/white, view doesn't update on css changes or HTML changes, animations are choppy 上的最后一个答案,他在 WebView 的 OnTouchEvent 上触发了几个延迟失效,而不是在 onDraw 上持续触发 ... webview 和我更改了一些 CSS 作为响应。当然,它根本不适用于自动/超时的 css

在我的例子中,它还有助于从 Java 导出一个 JavaScript 函数来手动触发延迟失效,所以如果在 JavaScript 中你或多或少知道灾难可能发生在哪里,你可以手动触发它,就像里面的这个内部类你的网络视图:

public class MyWebView extends WebView {

    private class InvalidateExtension {

        private Handler handler=new Handler(); // you might already have a handler
        private Runnable mInvalidater=new Runnable() {

            @Override
            public void run() {
                MyWebView.this.invalidate();
            }

        }

        public void trigger(int delay) {
                handler.postDelayed(mInvalidater, delay);
                handler.postDelayed(mInvalidater, 2*delay); // just in case
                handler.postDelayed(mInvalidater, 4*delay); // just in case just in case :)
        }
    }


    /** Call this function on this view's init, BEFORE loading a page so it is available to JS */
    private void call_me_on_init_to_enable_hack() {
        addJavascriptInterface(new InvalidateExtension(), "Invalidater");
    }
}

所以,从 JavaScript 你可以做到:

Invalidater.trigger(100);

并使用毫秒值....

希望这对某人有所帮助!

【讨论】:

    【解决方案4】:

    旋转手机时缩放比例有问题,会导致此问题,部分或整个页面将无法绘制。要在您的 WebViewClient 实现中解决此覆盖 onScaleChanged 并使视图无效。这应该会在需要时强制重绘。

    @Override
        public void onScaleChanged(WebView view, float oldScale, float newScale) {
            if (view != null) {
                view.invalidate();
            }
        }
    

    【讨论】:

      猜你喜欢
      • 2014-01-29
      • 2012-05-10
      • 1970-01-01
      • 2012-02-04
      • 2017-08-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多