it-swarm.com.de

Android WebView wird leer/weiß dargestellt, die Ansicht wird bei CSS-Änderungen oder HTML-Änderungen nicht aktualisiert. Animationen sind abgehackt

Wann immer ich eine CSS-Klassenänderung vornehme, werden die Änderungen nicht immer angezeigt. Dies scheint zu passieren, wenn ich ein Berührungsereignis habe, das einer Schaltfläche etwas wie einen Klassennamen hinzufügt. Die Schaltfläche wird nicht aktualisiert und auch sonst nichts auf der Seite. Es ist sehr unbeständig, wenn es funktioniert. Ich habe auch bemerkt, dass meine Elemente manchmal weiß ohne Inhalt oder irgendetwas erscheinen. Das ist sehr frustrierend!

50
Kyle

Ich habe die Lösung von kyle implementiert und das Problem gelöst. Allerdings fiel mir auf Android 4.0.4 ein riesiger Akku auf, als die App geöffnet war. Nach der Änderung klagte der Benutzer darüber, dass die Tastatur des SwiftKey nicht mehr mit meiner App funktioniert.

Jede Änderung in meiner App wird durch eine Benutzeraktion ausgelöst, sodass ich eine modifizierte Version gefunden habe, die invalidate () erst nach einem touchEvent auslöst:

    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();
        }
    };

Nie haben Sie mit Java programmiert, daher könnte es eine bessere Lösung dafür geben.

17
Olivier

Hinweis:
Ab Android 4.4+ gibt es eine bessere Lösung. Es handelt sich um eine WebViewname__-Ersetzung mit dem Namen CrossWalk . Es verwendet das neueste Chromium-Kit und ist fantastisch. Sie können es hier nachlesen: crosswalk-project.org

Außerdem scheint es, dass seit Android 4.4 die invalidate() -Lösung nicht mehr erforderlich ist und Sie einige der anderen sichereren Antworten verwenden können. Ich würde diesen invalidate() -Ansatz nur als letzten Versuch verwenden.


Ich beantworte meine eigene Frage, um Menschen mit den gleichen Problemen wie ich zu helfen.

Ich habe verschiedene Methoden ausprobiert, um die Dinge zu verbessern, sogar die allesamt berüchtigten -webkit-transform: translate3d(0,0,0); Auch das hat nicht allzu gut funktioniert.

Lassen Sie mich mit Ihnen teilen, was funktioniert hat.

Verwenden Sie zunächst die neueste API. Ich verwende API 15. Aktivieren Sie in Ihrem AndroidManifest.xml die Hardwarebeschleunigung . Wenn Ihre API-Version dies nicht unterstützt, fahren Sie mit dem nächsten Bit fort.

Wenn Ihre Version dies unterstützt, können Sie es aktivieren, indem Sie Ihr Manifest ändern:

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

Stellen Sie außerdem sicher, dass Ihr Manifest über die minimale unterstützte API für die von Ihnen verwendete verfügt. Da ich API 15 verwende, hat mein Manifest Folgendes:

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

( Update : Sie sollten diese Werte jetzt in Ihrem build.gradle) ändern.

Fügen Sie nun in Ihrer primären CSS-Datei für das, was in einer WebView angezeigt wird, Folgendes hinzu:

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

Ergänzen Sie das Body-Div-Bit mit allen anderen Elementtypen, die Sie haben. Sie können wahrscheinlich Bilder, ulname__, liusw. ausschließen. Der Grund für das Anwenden dieses CSS-Stils auf alles ist nur ein Versuch, und ich fand, dass das rohe Anwenden auf alles am besten funktioniert. Bei einem größeren DOM-Baum müssen Sie möglicherweise spezifischer vorgehen. Ich bin mir jedoch nicht sicher, wie die Spezifikation lauten würde.

Wenn Sie Ihren WebViewinstanziieren, gibt es einige Einstellungen, die Sie festlegen möchten:

@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);
}

Vorletzter, aber entscheidender Punkt: Ich habe den Quellcode für die Klasse WebViewdurchgelesen und diesen kleinen, winzigen Kommentar zum erzwungenen Neuzeichnen gefunden. Es gibt einen static final boolean, der bei Einstellung auf truedie Ansicht zwingt, immer neu zu zeichnen. Die Syntax von Java ist nicht besonders gut, aber ich glaube nicht, dass Sie ein statisches Endattribut einer Klasse direkt ändern können. Am Ende habe ich die Klasse folgendermaßen erweitert:

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();
    }

}

Denken Sie daran, dass ich Cordova/PhoneGap verwende, also musste ich von CordovaWebViewaus erweitern. Wenn Sie in der onDraw-Methode sehen, wird invalidateaufgerufen. Dadurch wird die Ansicht ständig neu gezeichnet. Ich empfehle dringend, Logik hinzuzufügen, um sie nur dann neu zu zeichnen, wenn Sie sie benötigen.

Wenn Sie Cordova verwenden, gibt es einen letzten Schritt. Sie müssen PhoneGap anweisen, Ihre neue Klasse WebViewanstelle ihrer eigenen Klasse WebViewzu verwenden. Fügen Sie in Ihrer Klasse MainActivityFolgendes hinzu:

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

Das ist es! Versuchen Sie, Ihre App auszuführen, und prüfen Sie, ob alles viel flüssiger ist. Bevor alle diese Änderungen vorgenommen wurden, sahen die Seiten weiß aus. Es wurden keine CSS-Änderungen vorgenommen, bis nach erneutem Tippen auf den Bildschirm die Animationen sehr abgehackt waren oder nicht einmal auffielen. Ich sollte erwähnen, dass die Animationen immer noch abgehackt sind, aber viel weniger abgehackt als zuvor.

Wenn jemand etwas hinzuzufügen hat, kommentieren Sie einfach unter. Ich bin immer offen für Optimierungen; und ich bin mir voll und ganz bewusst, dass es vielleicht bessere Möglichkeiten gibt, das zu tun, was ich gerade empfohlen habe.

Wenn meine obige Lösung für Sie nicht funktioniert hätte, könnten Sie Ihre spezifische Situation beschreiben und welche Ergebnisse sehen Sie mit Androids WebViewname__?

Zuletzt habe ich diese Antwort als "Community-Wiki" aktiviert, sodass jeder und jede sich frei fühlen kann, Anpassungen vorzunehmen.

Vielen Dank!


Bearbeiten:

Mit der neuesten Version von PhoneGap muss Ihre init () -Methode ungefähr so ​​aussehen:

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

re: Beim Neuzeichnen-Problem können Sie eine Neuzeichnung durch Lesen einer Eigenschaft aus dem Element erzwingen

also sag, du machst das:

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

wenn du das später machst:

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

es wird ein Neuzeichnen erzwingen.

Auf diese Weise können Sie selektiv vorgehen, anstatt die gesamte Seite ständig neu zu zeichnen, was teuer ist

8
Andrew Bullock

Für mich war dieses Problem nur bei Samsung-Geräten der Fall. Ich konnte das Problem beheben, indem ich die Hardwarebeschleunigung für WebViews deaktivieren:

webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

Ich hoffe es hilft.

8

Wie oben und anderswo dargelegt - das Überschreiben von View.onDraw() und das Aufrufen von View.invalidate führt zu einer unglücklichen Akku-/App-Leistung. Sie können auch einen manuellen Aufruf von invalidate mit x ms durchführen

/**
 * 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);
        }
    });
}

Ich habe versucht, einen Invalidierungsaufruf in WebViewClient.onPageLoaded() zu setzen, aber dies scheint nicht zu funktionieren. Während meine Lösung besser sein könnte, ist sie einfach und funktioniert für mich (ich zeige nur ein Twitter-Login).

6
Dori

Ich hatte dieses Problem, weil onPageStared und onPageFinished eine Lade-Animation anzeigen und ausblenden.

Da JS injiziert wurde, mache ich meine Menüs und Sachen von der ursprünglichen Website und bemerkte, dass das Injizieren von JS auf onPageFinished den Webview zwingt, Inhalte zu zeichnen. Hier ein Beispiel, was Sie am Ende von onPageFinished hinzufügen können

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

Löschen Sie einfach den Cache von webView in oncreate () und es funktioniert für mich.

webView.clearCache(true);
0
Ankush Chugh

Siehe auch meine Antwort unter WebView kann nicht gerendert werden, bis Android 4.2.2 berührt wird. Die Idee besteht darin, die Funktion von @ Olivier nach JavaScript zu exportieren, damit Sie in JS in sinnvollen Bereichen Ungültigkeitserklärungen auslösen können Hack !! :)

0
rupps