Android的WebView呈现空白/白色,视图不更新的CSS更改或HTML更改,animation是波涛汹涌

当我做一个CSS类更改时,更改不总是显示。 这似乎发生在我有一个触摸事件,添加类似下拉类名称的button。 该button不会更新,也不会在页面上进行其他操作。 什么时候工作是非常不稳定的。 我也注意到,有时我的元素显示为白色,没有内容或任何东西。 这非常令人沮丧!

我实施了凯尔的解决scheme,并解决了这个问题。 当应用程序打开时,我注意到Android 4.0.4上的电池电量耗尽。 更改后,我有用户抱怨swiftKey键盘不适用于我的应用程序了。

我的应用程序的每一个变化都是由一个用户动作触发的,所以我想出了一个修改后的版本,在touchEvent之后只触发invalidate():

Handler handler = new Handler(); public boolean onTouchEvent (MotionEvent event){ super.onTouchEvent(event); handler.postDelayed(triggerInvalidate, 60); handler.postDelayed(triggerInvalidate, 300); return true; } private Runnable triggerInvalidate=new Runnable(){ public void run(){ invalidate(); } }; 

从来没有使用Java编程,所以可能有更好的解决scheme来做到这一点。

注意:
Android 4.4+还有更好的解决scheme。 这是一个名为CrossWalk的embedded式 WebView替代 。 它使用最新的Chromium套件,这太棒了。 你可以在这里阅读: crosswalk-project.org

而且,从Android 4.4开始, invalidate()解决scheme不再是必需的,您可以使用其他更安全的答案。 我只会使用这个invalidate()方法作为最后的努力。


我正在回答自己的问题,希望能帮助人们解决和我一样的问题。

我已经尝试了几种方法来使事情变得更好,甚至是所有臭名昭着的 – webkit-transform: translate3d(0,0,0); 即使这样也不行。

让我分享一下你的工作。

首先,使用最新的API。 我正在使用API​​ 15.在您的AndroidManifest.xml ,确保启用硬件加速 。 如果你的API版本不支持这个,那么继续下一步。

如果你的版本支持它,你可以通过修改你的清单来启用它:

 <application ... android:hardwareAccelerated="true"> 

此外,请确保您的清单具有您正在使用的最低支持的API。 由于我使用API​​ 15,这是我的清单所具有的:

 <uses-sdk android:minSdkVersion="15" android:targetSdkVersion="15" /> 

更新 :您现在应该修改您的build.gradle中的值)

现在,在您的主要CSS文件中将呈现在WebView中,添加如下所示:

 body div { -webkit-transform: translate3d(0,0,0); } 

使用任何其他元素types添加到body div位; 你也许可以排除图像, ulli等等。将CSS样式应用于所有事情的原因只是反复试验,我发现将它应用于所有事物看起来效果最好。 对于更大的DOM树,您可能需要更具体。 不过,我不确定规格是什么。

当你实例化你的WebView ,你需要设置一些设置:

 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); super.loadUrl("file:///android_asset/www/index.html"); appView.getSettings().setRenderPriority(RenderPriority.HIGH); appView.getSettings() .setPluginState(WebSettings.PluginState.ON_DEMAND); } 

倒数第二,但至关重要的一点是:我正在阅读WebView类的源代码,并发现这个关于强制重绘的小小的评论。 有一个static final boolean ,当设置为true将强制视图总是重绘。 我在Java语法上并不是很大,但是我不认为你可以直接改变一个类的静态final属性。 所以我最终做的是扩展了这个类:

 import org.apache.cordova.CordovaWebView; import android.content.Context; import android.graphics.Canvas; public class MyWebView extends CordovaWebView { public static final String TAG = "MyWebView"; public MyWebView(Context context) { super(context); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // Warning! This will cause the WebView to continuously be redrawn // and will drain the devices battery while the view is displayed! invalidate(); } } 

请记住,我正在使用Cordova / PhoneGap,所以我不得不从CordovaWebView扩展。 如果你在onDraw方法中看到有一个调用invalidate 。 这将导致视图不断重绘。 不过,我强烈build议你在需要的时候添加逻辑来重绘。

如果您使用cordova,还有最后一步。 您必须告诉PhoneGap使用新的WebView类而不是自己的WebView类。 在你的MainActivity类中,添加这个:

 public void init(){ CordovaWebView webView = new MyWebView(MainActivity.this); super.init(webView, new CordovaWebViewClient(this, webView), new CordovaChromeClient(this, webView)); } 

而已! 尝试并运行你的应用程序,看看是否一切都更顺畅。 在进行所有这些更改之前,页面将显示为白色,不会再应用CSS更改,直到再次点击屏幕后,animation超级波动或甚至不明显。 我应该提到,animation仍然是波涛汹涌,但比以前less得多。

如果有人有任何补充,只需在下面评论。 我总是打开优化; 我完全意识到可能有更好的方法去做我刚刚推荐的。

如果我的上述解决scheme不适合您,您能描述一下您的具体情况,以及您使用Android WebView看到的结果吗?

最后,我已经把这个答案作为“社区wiki” ,所以任何人和每个人都可以自由地做出调整。

谢谢!


编辑:

使用最新的PhoneGap,你需要让你的init()方法看起来更像这样:

 public void init(){ CordovaWebView webView = new MyWebView(MainActivity.this); super.init(webView, new IceCreamCordovaWebViewClient(this, webView), new CordovaChromeClient(this, webView)); } 

re:重画问题,你可以通过从元素中读取一个属性来强制重画

所以说你这样做:

 $('#myElement').addClass('foo'); // youre not seeing this take effect 

如果你事后这样做:

 $('#myElement').width(); 

它会强制重绘。

这样你就可以有select地重绘整个页面,而这一切都是昂贵的

对我来说,这个问题只发生在三星设备上。 我能够通过禁用WebViews的硬件加速来修复它:

 webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); 

希望它有帮助。

正如上面和其他地方指出的 – 覆盖View.onDraw()和调用View.invalidate将使一个不愉快的电池/应用程序性能下降。 你也可以像这样做x毫秒手动invalidate呼叫

 /** * Due to bug in 4.2.2 sometimes the webView will not draw its contents after the data has loaded. * Triggers redraw. Does not work in webView's onPageFinished callback for some reason */ private void forceWebViewRedraw() { mWebView.post(new Runnable() { @Override public void run() { mWebView.invalidate(); if(!isFinishing()) mWebView.postDelayed(this, 1000); } }); } 

我试着在WebViewClient.onPageLoaded()放入一个invalidate调用,但是这似乎不起作用。 虽然我的解决scheme可以更好的简单,它适用于我(即时通讯只是显示一个微博login)

也请看看我的答案在WebView无法呈现,直到触及Android 4.2.2 ,这个想法是导出@ Olivier的functionJavaScript,所以你可以从敏感的部分触发JS失效…我的天,还有更多的黑客! 🙂

我有这个问题,因为onPageStared和onPageFinished我显示并隐藏加载animation。

自从注入JS做我的菜单和东西从原来的网站,并注意到在onPageFinished注入JS强制Web视图来绘制内容。 这是一个你可以添加在onPageFinished结束的例子

 view.loadUrl("javascript:(function() { var select = document.getElementsByClassName('something')[0]\r\n" + " if(select)" + " select.style.display = 'none';})()");