cordova Android WebView呈现为空白/白色,视图不随css更改或HTML更改而更新,动画不连贯

hwazgwia  于 2022-11-15  发布在  Android
关注(0)|答案(9)|浏览(187)

当我对css类进行更改时,这些更改并不总是出现。当我有一个touch事件,在按钮上添加了一个down类名称之类的东西时,就会出现这种情况。按钮不会更新,页面上的其他东西也不会更新。它工作的时候非常不稳定。我还注意到,有时我的元素会显示为白色,没有内容或任何东西。这非常令人沮丧!

xpszyzbs

xpszyzbs1#

备注:

Android 4.4+有一个更好的解决方案。它是一个称为 CrossWalkWebView替代品。它使用了最新的Chromium套件,非常棒。你可以在这里阅读它:crosswalk-project.org
而且,自从Android 4.4以来,invalidate()解决方案似乎不再是必要的,你可以使用其他一些更安全的解决方案。
我在回答我自己的问题,希望能帮助那些和我有同样问题的人。
我已经尝试了几种方法来让事情变得更好,甚至是所有臭名昭著的-webkit-transform: translate3d(0,0,0);,即使这样也没有工作得太好。
让我来和大家分享一下哪些方法有效。
首先,使用最新的API。我使用的是API 15。在您的AndroidManifest.xml中,请确保启用 * 硬件加速 *。如果您的API版本不支持此功能,请转到下一位。
如果您的版本支持它,则可以通过修改清单来启用它:

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

另外,确保您的manifest具有您正在使用的最低支持API。由于我使用的是API 15,因此我的manifest具有以下内容:

<uses-sdk
    android:minSdkVersion="15"
    android:targetSdkVersion="15" />
  • 更新:您现在应该修改build.gradle)* 中值

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

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

将其他元素类型添加到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的调用。这将导致视图不断地重绘。但是,我强烈建议添加逻辑,以便只在需要时重绘。
最后一步,如果你使用的是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更改会被应用,直到再次点击屏幕后,动画超级不稳定,甚至不明显。我应该提到的是,动画仍然不稳定,但比以前少了很多。
如果有人对此有任何补充,请在下面评论。我完全意识到可能有更好的方法来做我刚才推荐的事情。
如果我的上述解决方案对您不起作用,您能否描述一下您的具体情况,以及您在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));
}
zbq4xfa0

zbq4xfa02#

我实施了凯尔的解决方案,它解决了这个问题。然而,我注意到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编程过,所以可能有更好的解决方案来做到这一点。

ru9i0ody

ru9i0ody3#

re:重绘问题,您可以通过从元素阅读属性来强制重绘
假设您这样做:

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

如果以后执行此操作:

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

它将强制重绘。
这样,您就可以有选择性地重新绘制整个页面,而不是一直重新绘制整个页面,这是非常昂贵的

js81xvg6

js81xvg64#

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

webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

希望能有所帮助。

i2byvkas

i2byvkas5#

正如上面和其他地方所指出的-覆盖View.onDraw()和调用View.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()中放置一个无效调用,但这似乎不起作用。虽然我的解决方案可以更好,但它很简单,对我很有效(我只是显示一个Twitter登录)

fdbelqdn

fdbelqdn6#

请也看到我的回答在WebView无法渲染,直到触摸Android 4.2.2,这个想法是导出@奥利维尔的函数到JavaScript,这样你就可以触发从JS在明智的部分无效...我的上帝,又一个黑客!!:)

bihw5rsg

bihw5rsg7#

我遇到这个问题是因为onPageStared和onPageFinished显示和隐藏了一个加载动画。
因为是从原始网站注入JS做我的菜单和东西,并注意到在onPageFinished上注入JS强制webview绘制内容。

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

iszxjhcz8#

只要清除oncreate()中的webView缓存,它就对我有效。

webView.clearCache(true);
laik7k3q

laik7k3q9#

您应该通过修改清单来启用硬件:

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

在您的活动onResume()中

webView.postDelayed(() -> {
    if (!isFinishing() && webView != null) {
        webView.setLayerType(View.LAYER_TYPE_NONE, null);
    }
}, 1000);

而在onPause()中

webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

相关问题