Android WebView呈现空白/白色,视图不会更新css更改或HTML更改,动画不稳定

Kyl*_*yle 51 html css android cordova

当我进行css类更改时,更改并不总是出现.当我有一个触摸事件向按钮添加类别如下课名称时,就会发生这种情况.该按钮不会更新,也不会在页面上执行任何其他操作.它何时起作用是非常不稳定的.我也注意到有时我的元素看起来是白色的,没有内容或任何东西.这非常令人沮丧!

Kyl*_*yle 58

注意:
从Android 4.4+开始,有一个更好的解决方案.这是一个WebView名为CrossWalk的替代.它使用最新的Chromium-kit,非常棒.你可以在这里阅读:crosswalk-project.org

此外,似乎自Android 4.4以来,invalidate()解决方案已不再需要,您可以使用其他更安全的答案.我只会用这种invalidate()方法作为最后的努力.


我正在回答我自己的问题,希望能帮助别人解决与我相同的问题.

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

让我与大家分享一些有用的工作.

首先,使用最新的API.我正在使用API​​ 15.在您的工作中AndroidManifest.xml,请确保启用硬件加速.如果您的API版本不支持此功能,请转到下一位.

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

<application
   ...
   android:hardwareAccelerated="true">
Run Code Online (Sandbox Code Playgroud)

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

<uses-sdk
    android:minSdkVersion="15"
    android:targetSdkVersion="15" />
Run Code Online (Sandbox Code Playgroud)

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

现在,在您的主要CSS文件中,将在WebView中显示,添加如下内容:

body div {
    -webkit-transform: translate3d(0,0,0);
}
Run Code Online (Sandbox Code Playgroud)

使用您拥有的任何其他元素类型添加到body div位; 你可能可以排除图像ul,li等,其原因应用此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);
}
Run Code Online (Sandbox Code Playgroud)

倒数第二,但关键点:我正在阅读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();
    }

}
Run Code Online (Sandbox Code Playgroud)

请记住,我正在使用Cordova/PhoneGap,所以我不得不延长CordovaWebView.如果您在onDraw方法中看到,则会调用invalidate.这将导致视图不断重绘.但我强烈建议您在需要时添加逻辑以仅重绘.

如果您使用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));
}
Run Code Online (Sandbox Code Playgroud)

而已!尝试并运行您的应用程序,看看是否一切都更顺畅.在进行所有这些更改之前,页面将显示为白色,直到再次点击屏幕后才会应用CSS更改,动画非常不稳定或甚至不明显.我应该提一下,动画仍然不稳定,但远不如以前那么波动.

如果有人要添加任何内容,请在下面发表评论.我总是乐于接受优化; 而且我完全清楚可能有更好的方法来做我刚推荐的事情.

如果我的上述解决方案不适合您,您能否描述一下您的具体情况以及您对Androids的看法WebView

最后,我已将此答案作为"社区维基"启用,因此任何人和所有人都可以随意进行调整.

谢谢!


编辑:

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

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

  • 只需注意,在onDraw上调用invalidate意味着您的webview将不断重绘.不是最好的主意. (11认同)
  • 我将要求Joe查看您的答案,也许这将是一个好主意,包含在CordovaWebView代码中. (4认同)
  • -webkit-transform:translate3d(0,0,0); 拯救了一天..甚至在Chromium上.这可以纠正打开硬件加速后空白的设备的渲染问题.我使用setLayerType(View.LAYER_TYPE_NONE,null); 所以在某些设备上不会发生这种情况. (3认同)

小智 17

我实现了凯尔的解决方案,它解决了这个问题.Howewer我注意到应用程序打开时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();
        }
    };
Run Code Online (Sandbox Code Playgroud)

从未使用Java进行任何编程,因此可能有更好的解决方案来执行此操作.

  • 电池消耗是由于视图不断重绘.该解决方案完全缓解了这一点.因为这个原因,我强烈建议不要使用所选答案. (3认同)

And*_*ock 8

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

所以说你这样做:

$('#myElement').addClass('foo'); // youre not seeing this take effect
Run Code Online (Sandbox Code Playgroud)

如果你之后这样做:

$('#myElement').width();
Run Code Online (Sandbox Code Playgroud)

它会强制重绘.

这样你就可以选择性而不是一直重绘整个页面,这很昂贵


Lea*_*man 8

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

webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你.


Dor*_*ori 6

正如上面和其他地方所指出的那样 - 覆盖View.onDraw()和调用View.invalidate将使不满意的电池/应用程序性能下降.您也可以invalidate像x 这样进行手动呼叫

/**
 * 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);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

我尝试了一个无效的调用,WebViewClient.onPageLoaded()但这似乎不起作用.虽然我的解决方案可能更好,但它适用于我(我只是显示一个Twitter登录)