Wie kann ich auf ein WebView warten, das das Laden einer URL beendet?

447

Ich habe eine WebView, die eine Seite aus dem Internet lädt. Ich möchte ein anzeigen, ProgressBarbis das Laden abgeschlossen ist.

Wie höre ich auf den Abschluss des Seitenladens von a WebView?

Janusz
quelle
1
Bitte erwägen Sie, meine Antwort als richtig zu markieren, da dies einige Probleme löst, die ian nicht hat.
Neteinstein
Ich denke, eine bessere Möglichkeit, den nativen Java-Code mit js aufzurufen, wenn die Seite geladen wird. Verweisen Sie auf diese Antwort, obwohl es für ios ist, aber die Idee gilt auch hier .
Kris Roofe
Überprüfen Sie meine Antwort unten für minimale und prägnante Lösung
Skynet

Antworten:

715

Erweitern Sie WebViewClient und rufen Sie onPageFinished () wie folgt auf:

mWebView.setWebViewClient(new WebViewClient() {

   public void onPageFinished(WebView view, String url) {
        // do your stuff here
    }
});
Ian
quelle
Ich habe einige Probleme mit externen Ladevorgängen, wenn das Internet nicht so schnell ist. Zum Beispiel Google Analytics oder ähnliches. Ich habe einige Problemumgehungen ausprobiert und es hat sich stark verbessert, ist aber noch nicht perfekt. Manchmal friert die App beim Laden des Bildschirms ein und es ist unmöglich, sie zu beenden, es sei denn, Sie trennen das Netzwerk oder stellen eine Verbindung zu einem anderen guten her. Ich weiß noch nicht, wie ich das lösen soll, ich versuche es.
Felipe
1
Funktioniert perfekt. Sie können mWebView.setVisibility (View.INVISIBLE) vor dem Laden verwenden. Wenn der Ladevorgang abgeschlossen ist, setzen Sie ihn wieder auf View.VISIBLE. Ich habe es mit diesem Begrüßungsbildschirm verwendet
Johan Hoeksma
39
Dies ist überhaupt keine Lösung. Es gibt keine Garantie dafür, dass die Seite bereits geladen ist, wenn diese Methode aufgerufen wird.
Hawk
3
Dies ist ein so schlechtes Design von Google. Fast immer, wenn diese Aktion abgeschlossen ist, möchten Sie etwas tun, das sich an der übergeordneten Aktivität orientiert, nicht an der Webansicht selbst. Das Überschreiben einer Funktion, anstatt ein Ereignis zu abonnieren, ist ein häufiges Anti-Muster und ein Grund, warum ich die Android-Entwicklung nicht mag.
Ryan
6
Diese Methode garantiert nicht das Beenden des Ladevorgangs und kann mehrmals aufgerufen werden, wenn das Laden der URL eine Zwischen-URL-Navigation erfordert. Das wird also mehrmals aufgerufen. Es ist jedoch eine Möglichkeit, dies zu überprüfen.
Anfänger
150

@ian das ist nicht 100% genau. Wenn Sie mehrere Iframes auf einer Seite haben, haben Sie mehrere onPageFinished (und onPageStarted). Und wenn Sie mehrere Weiterleitungen haben, kann dies ebenfalls fehlschlagen. Dieser Ansatz löst (fast) alle Probleme:

boolean loadingFinished = true;
boolean redirect = false;

mWebView.setWebViewClient(new WebViewClient() {

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String urlNewString) {
        if (!loadingFinished) {
            redirect = true;
        }

        loadingFinished = false;
        webView.loadUrl(urlNewString);
        return true;
    }

    @Override
    public void onPageStarted(WebView view, String url) {
        loadingFinished = false;
        //SHOW LOADING IF IT ISNT ALREADY VISIBLE  
    }

    @Override
    public void onPageFinished(WebView view, String url) {
        if (!redirect) {
           loadingFinished = true;
            //HIDE LOADING IT HAS FINISHED
        } else {
            redirect = false; 
        }
    }
});

AKTUALISIEREN:

Gemäß der Dokumentation: onPageStarted wird NICHT aufgerufen, wenn sich der Inhalt eines eingebetteten Frames ändert, dh wenn Sie auf einen Link klicken, dessen Ziel ein Iframe ist.

Ich habe einen solchen speziellen Fall auf Twitter gefunden, in dem nur eine pageFinished aufgerufen wurde und die Logik ein wenig durcheinander gebracht hat. Um dies zu lösen, habe ich eine geplante Aufgabe hinzugefügt, um das Laden nach X Sekunden zu entfernen. Dies ist in allen anderen Fällen nicht erforderlich.

UPDATE 2 :

Jetzt mit der aktuellen Android WebView-Implementierung:

boolean loadingFinished = true;
boolean redirect = false;

    mWebView.setWebViewClient(new WebViewClient() {

        @Override
        public boolean shouldOverrideUrlLoading(
                WebView view, WebResourceRequest request) {
            if (!loadingFinished) {
               redirect = true;
            }

            loadingFinished = false;
            webView.loadUrl(request.getUrl().toString());
            return true;
        }

        @Override
        public void onPageStarted(
                WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
            loadingFinished = false;
            //SHOW LOADING IF IT ISNT ALREADY VISIBLE  
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            if (!redirect) {
               loadingFinished = true;
                //HIDE LOADING IT HAS FINISHED
            } else {
                redirect = false; 
            }
        }
    });
neteinstein
quelle
3
Sie haben wahrscheinlich die Einschränkung in onPageStarteds Dokument bemerkt: onPageStarted wird NICHT aufgerufen, wenn sich der Inhalt eines eingebetteten Frames ändert, dh wenn Sie auf einen Link klicken, dessen Ziel ein Iframe ist. Dies kann in diesen Fällen die Logik verzerren. Übrigens, funktioniert die Vereinfachung von @ polen wirklich?
an00b
1
Netter Fang, habe das Rahmenzeug nie bemerkt. Ich habe den Polen-Code nicht ausprobiert. Das einzige, was ich versichern kann, ist, dass es das oben genannte ist, das ich verwende.
Neteinstein
3
Nur eine kleine Korrektur. Es ist eigentlich "public void onPageStarted (WebView-Ansicht, String-URL, Bitmap-Favicon)" anstelle von "public void onPageStarted (WebView-Ansicht, String-URL)"
MrMaffen
Funktioniert nicht für einige der neueren Websites, die das Laden nie beenden ... z. B. "agoda.com". Sie erhalten den Aufruf onPageFinished nie, da es sich um eine Umleitung handelt.
Kenyee
Ich habe gesehen, dass onPageFinished während einer Umleitung zweimal aufgerufen wurde. Was Sie jedoch gesagt haben "Wenn Sie mehrere Iframes auf einer Seite haben, haben Sie mehrere onPageFinished (und onPageStarted)", ist gemäß der Dokumentation von onPageFinished nicht richtig: "Diese Methode wird nur für den Hauptframe aufgerufen."
Granat
40

Ich bin ziemlich angetan von der Lösung @NeTeInStEiN (und @polen), hätte sie aber mit einem Zähler anstelle mehrerer Boolescher Werte oder Statusbeobachter implementiert (nur eine andere Variante, von der ich dachte, dass sie geteilt werden könnte). Es hat eine JS-Nuance, aber ich denke, die Logik ist etwas einfacher zu verstehen.

private void setupWebViewClient() {
    webView.setWebViewClient(new WebViewClient() {
        private int running = 0; // Could be public if you want a timer to check.

        @Override
        public boolean shouldOverrideUrlLoading(WebView webView, String urlNewString) {
            running++;
            webView.loadUrl(urlNewString);
            return true;
        }

        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            running = Math.max(running, 1); // First request move it to 1.
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            if(--running == 0) { // just "running--;" if you add a timer.
                // TODO: finished... if you want to fire a method.
            }
        }
    });
}
SciSpear
quelle
2
Ihr Code sieht gut aus. Ich habe das gleiche für meine Webansicht versucht, die aus HTML-Daten nicht URL lädt. Dieser löst jedoch onPageFinished aus, wenn die erste Webansicht schnell geladen wird und bevor die zweite geladen wird. Normales Szenario. running = 1, running = 2, --running = 1, --running = 0. Ungewöhnliches Szenario, das fehlschlägt - Laufen = 1, - Laufen = 0, Laufen = 1 Laufen = 0
Ajith Memana
1
Es gibt auch ein anderes Szenario, in dem der TODO-Teil niemals erreicht wird, wenn ein Ereignis aus irgendeinem Grund nicht ausgelöst wird. Sie benötigen also einen Timer, um nach Zeitüberschreitungen zu suchen. Oder Sie können eine exportierte Java-Funktion in Javascript aufrufen, wenn Sie wissen, dass alles richtig geladen ist. So etwas wie documentReady () oder so ähnlich.
Codebeat
warum nicht einfach running = 1;rein onPageStarted()?
Choletski
@Choletski Weil das Maximum von 1 und eine Zahl größer als 1 nicht 1 ist.
Matthew Read
25

Ich habe auch eine elegante Lösung gefunden, habe sie aber nicht rigoros getestet:

public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            if (m_webView.getProgress() == 100) {
                progressBar.setVisibility(View.GONE);
                m_webView.setVisibility(View.VISIBLE);
            }
        } 
Skynet
quelle
2
Ich habe es getestet und es funktioniert einwandfrei. Sie können es natürlich von außerhalb der onPageFinished-Methode aufrufen und einen Handler verwenden, um in kurzen Intervallen zu prüfen. In einigen Fällen möchten Sie die WebViewClient-Klasse nicht erweitern.
Gal Rom
1
Ich glaube, dies ist möglicherweise besser als die akzeptierte Antwort. Sie müssen nur den onError überprüfen und sind fertig.
Evin1_
1
Dies sollte die akzeptierte Antwort sein.
زياد
1
Upvote für diesen
Khdkls
23

Ich habe den Code von NeTeInStEiN so vereinfacht :

mWebView.setWebViewClient(new WebViewClient() {
        private int       webViewPreviousState;
        private final int PAGE_STARTED    = 0x1;
        private final int PAGE_REDIRECTED = 0x2;

        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String urlNewString) {
            webViewPreviousState = PAGE_REDIRECTED;
            mWebView.loadUrl(urlNewString);
            return true;
        }

        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
            webViewPreviousState = PAGE_STARTED;
            if (dialog == null || !dialog.isShowing())
                dialog = ProgressDialog.show(WebViewActivity.this, "", getString(R.string.loadingMessege), true, true,
                        new OnCancelListener() {

                            @Override
                            public void onCancel(DialogInterface dialog) {
                                // do something
                            }
                        });
        }

        @Override
        public void onPageFinished(WebView view, String url) {

            if (webViewPreviousState == PAGE_STARTED) {
                dialog.dismiss();
                dialog = null;
            }

        }
 });

Es ist leicht zu verstehen, OnPageFinished, wenn der vorherige Rückruf auf onPageStarted erfolgt, sodass die Seite vollständig geladen ist.

polen
quelle
3
@polen PAGE_STARTED wird nie gelöscht? Was ist, wenn shouldOverrideUrlLoading () niemals aufgerufen wird?
an00b
20

Wenn Sie einen Fortschrittsbalken anzeigen möchten, müssen Sie auf ein Fortschrittsänderungsereignis warten, nicht nur auf die Fertigstellung der Seite:

mWebView.setWebChromeClient(new WebChromeClient(){

            @Override
            public void onProgressChanged(WebView view, int newProgress) {

                //change your progress bar
            }


        });

Übrigens, wenn Sie nur eine unbestimmte Fortschrittsanzeige anzeigen möchten, die die Methode onPageFinished überschreibt, ist dies ausreichend

Francesco Laurita
quelle
5

Sie können den Progress Staus mithilfe der getProgress- Methode in der Webview- Klasse verfolgen .

Initialisieren Sie den Fortschrittsstatus

private int mProgressStatus = 0;

dann die AsyncTask zum Laden wie folgt:

private class Task_News_ArticleView extends AsyncTask<Void, Void, Void> {
    private final ProgressDialog dialog = new ProgressDialog(
            your_class.this);

    // can use UI thread here
    protected void onPreExecute() {
        this.dialog.setMessage("Loading...");
        this.dialog.setCancelable(false);
        this.dialog.show();
    }

    @Override
    protected Void doInBackground(Void... params) {
        try {
            while (mProgressStatus < 100) {
                mProgressStatus = webview.getProgress();

            }
        } catch (Exception e) {

        }
        return null;

    }

    protected void onPostExecute(Void result) {
        if (this.dialog.isShowing()) {
            this.dialog.dismiss();
        }
    }
}
Praveen
quelle
mProgressStatus = webview.getProgress (); muss von einem UI-Thread aufgerufen werden.
Skynet
5

Danke für die Antworten. Es hat mir geholfen, aber ich musste es ein bisschen für meine Bedürfnisse verbessern. Ich hatte mehrere Seitenstarts und Endungen, also habe ich einen Timer hinzugefügt, der prüft, ob nach dem Start der Seite ein neuer Seitenstart gestartet wird. Okay, schlechte Erklärung. Siehe den Code :)

myWebView.setWebViewClient(new WebViewClient() {
        boolean loadingFinished = true;
        boolean redirect = false;

        long last_page_start;
        long now;

        // Load the url
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            if (!loadingFinished) {
                redirect = true;
            }

            loadingFinished = false;
            view.loadUrl(url);
            return false;
        }

        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            Log.i("p","pagestart");
            loadingFinished = false;
            last_page_start = System.nanoTime();
            show_splash();
        }

        // When finish loading page
        public void onPageFinished(WebView view, String url) {
            Log.i("p","pagefinish");
            if(!redirect){
                loadingFinished = true;
            }
            //call remove_splash in 500 miSec
            if(loadingFinished && !redirect){
                now = System.nanoTime();
                new android.os.Handler().postDelayed(
                        new Runnable() {
                            public void run() {
                                remove_splash();
                            }
                        },
                        500);
            } else{
                redirect = false;
            }
        }
        private void show_splash() {
            if(myWebView.getVisibility() == View.VISIBLE) {
                myWebView.setVisibility(View.GONE);
                myWebView_splash.setVisibility(View.VISIBLE);
            }
        }
        //if a new "page start" was fired dont remove splash screen
        private void remove_splash() {
            if (last_page_start < now) {
                myWebView.setVisibility(View.VISIBLE);
                myWebView_splash.setVisibility(View.GONE);
            }
        }

});
EscapeNetscape
quelle
2

Hier ist eine neuartige Methode zum Erkennen, wenn eine URL geladen wurde, indem die Android-Funktion für JavaScript-Hooks verwendet wird . Mit diesem Muster nutzen wir das Wissen von JavaScript über den Status des Dokuments, um einen nativen Methodenaufruf innerhalb der Android-Laufzeit zu generieren. Diese JavaScript-zugänglichen Aufrufe können mithilfe der @JavaScriptInterfaceAnmerkung erfolgen.

Diese Implementierung erfordert, dass wir setJavaScriptEnabled(true)die WebViewEinstellungen des Benutzers aufrufen , sodass sie abhängig von den Anforderungen Ihrer Anwendung, z. B. Sicherheitsbedenken , möglicherweise nicht geeignet ist .

src / io / github / cawfree / webviewcallback / MainActivity.java (Jelly Bean, API Level 16)

package io.github.cawfree.webviewcallback;

/**
 *  Created by Alex Thomas (@Cawfree), 30/03/2017.
 **/

import android.net.http.SslError;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.JavascriptInterface;
import android.webkit.SslErrorHandler;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;

/** An Activity demonstrating how to introduce a callback mechanism into Android's WebView. */
public class MainActivity extends AppCompatActivity {

    /* Static Declarations. */
    private static final String HOOK_JS             = "Android";
    private static final String URL_TEST            = "http://www.zonal.co.uk/";
    private static final String URL_PREPARE_WEBVIEW = "";

    /* Member Variables. */
    private WebView mWebView = null;

    /** Create the Activity. */
    @Override protected final void onCreate(final Bundle pSavedInstanceState) {
        // Initialize the parent definition.
        super.onCreate(pSavedInstanceState);
        // Set the Content View.
        this.setContentView(R.layout.activity_main);
        // Fetch the WebView.
        this.mWebView = (WebView)this.findViewById(R.id.webView);
        // Enable JavaScript.
        this.getWebView().getSettings().setJavaScriptEnabled(true);
        // Define the custom WebClient. (Here I'm just suppressing security errors, since older Android devices struggle with TLS.)
        this.getWebView().setWebViewClient(new WebViewClient() { @Override     public final void onReceivedSslError(final WebView pWebView, final SslErrorHandler pSslErrorHandler, final SslError pSslError) { pSslErrorHandler.proceed(); } });
        // Define the WebView JavaScript hook.
        this.getWebView().addJavascriptInterface(this, MainActivity.HOOK_JS);
        // Make this initial call to prepare JavaScript execution.
        this.getWebView().loadUrl(MainActivity.URL_PREPARE_WEBVIEW);
    }

    /** When the Activity is Resumed. */
    @Override protected final void onPostResume() {
        // Handle as usual.
        super.onPostResume();
        // Load the URL as usual.
        this.getWebView().loadUrl(MainActivity.URL_TEST);
        // Use JavaScript to embed a hook to Android's MainActivity. (The onExportPageLoaded() function implements the callback, whilst we add some tests for the state of the WebPage so as to infer when to export the event.)
        this.getWebView().loadUrl("javascript:" + "function onExportPageLoaded() { " + MainActivity.HOOK_JS + ".onPageLoaded(); }" + "if(document.readyState === 'complete') { onExportPageLoaded(); } else { window.addEventListener('onload', function () { onExportPageLoaded(); }, false); }");
    }

    /** Javascript-accessible callback for declaring when a page has loaded. */
    @JavascriptInterface @SuppressWarnings("unused") public final void onPageLoaded() {
        // Display the Message.
        Toast.makeText(this, "Page has loaded!", Toast.LENGTH_SHORT).show();
    }

    /* Getters. */
    public final WebView getWebView() {
        return this.mWebView;
    }

}

res / layout / activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<WebView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/webView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
/>

Im Wesentlichen fügen wir eine zusätzliche JavaScript-Funktion hinzu, mit der der Status des Dokuments getestet wird. Wenn es geladen ist, starten wir ein benutzerdefiniertes onPageLoaded()Ereignis in Android MainActivity; Andernfalls registrieren wir einen Ereignis-Listener, der Android aktualisiert, sobald die Seite fertig ist window.addEventListener('onload', ...);.

Da wir dieses Skript nach dem Aufruf sind Anfügen an this.getWebView().loadURL("")gemacht worden ist , ist es wahrscheinlich , dass wir nicht brauchen zu ‚hören‘ überhaupt für die Ereignisse, da wir nur eine Chance, den JavaScript - Haken anzuzuhängen , indem sie einen sukzessiven Aufruf loadURL, sobald die Seite bereits geladen wurde.

Mapsy
quelle
Tolle Lösung, die im Allgemeinen funktioniert. Ich habe Probleme mit https://reddit.com/r/Nature (mit Reddit im Allgemeinen). Wenn Sie auf einen Thread klicken und der Thread geladen wird, kann ich dieses Ereignis nicht abfangen. Kannst du mir helfen?
Primož Kralj
@ PrimožKralj Glad Sie haben zu hören , etwas Erfolg mit diesem ... Ich bin mir nicht sicher , was speziell vorschlagen, aber wenn es irgendeine Art von öffentlichen Veranstaltungen , die Sie wissen , ausgelöst werden, dass Sie in, zum Beispiel Haken, wenn die Die Anzahl der Kommentare wird aktualisiert. Sie können diese als Quelle verwenden. Haben Sie darüber nachgedacht, dass Ihr Problem möglicherweise behoben werden könnte, indem Sie direkt auf die Reddit- API klicken?
Mapsy
1
Danke, ich werde mir die ausgelösten Ereignisse noch einmal ansehen und versuchen, mich an eines von ihnen zu binden. Ich kenne die API und werde versuchen, in Zukunft eine robustere Lösung zu implementieren. Vielen Dank!
Primož Kralj
1

Nur um den Fortschrittsbalken anzuzeigen, reichen die Methoden "onPageStarted" und "onPageFinished" aus. Wenn Sie jedoch ein "is_loading" -Flag (zusammen mit Seitenumleitungen, ...) haben möchten, werden diese Methoden möglicherweise ohne Sequenzierung ausgeführt, z. B. "onPageStarted> onPageStarted> onPageFinished> onPageFinished".

Bei meinem kurzen Test (testen Sie es selbst) lautet die Warteschlange für die Methodenwerte "onProgressChanged" "0-100> 0-100> 0-100> ...".

private boolean is_loading = false;

webView.setWebChromeClient(new MyWebChromeClient(context));

private final class MyWebChromeClient extends WebChromeClient{
    @Override
    public void onProgressChanged(WebView view, int newProgress) {
        if (newProgress == 0){
            is_loading = true;
        } else if (newProgress == 100){
            is_loading = false;
        }
        super.onProgressChanged(view, newProgress);
    }
}

Setzen Sie is_loading = falsebeim Schließen der Aktivität auch " ", wenn es sich um eine statische Variable handelt, da die Aktivität vor dem Ende der Seite beendet werden kann.

Jalil Hamdollahi Oskouei
quelle
0

Laden URL mit SwipeRefreshLayoutund ProgressBar:

UrlPageActivity.java:

    WebView webView;
    SwipeRefreshLayout _swipe_procesbar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_url_page);


        String url = "http://stackoverflow.com/";

        _swipe_procesbar = (SwipeRefreshLayout)findViewById(R.id.url_path_swipe_procesbar);

        _swipe_procesbar.post(new Runnable() {
                                  @Override
                                  public void run() {
                                      _swipe_procesbar.setRefreshing(true);
                                  }
                              }
        );

        webView = (WebView) findViewById(R.id.url_page_web_view);
        webView.getSettings().setJavaScriptEnabled(true);

        webView.setWebViewClient(new WebViewClient() {
            public void onPageFinished(WebView view, String url) {
                _swipe_procesbar.setRefreshing(false);
                _swipe_procesbar.setEnabled(false);
            }
        });
        webView.loadUrl(url);
    }

activity_url_page.xml:

<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/url_path_swipe_procesbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
        <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context="com.test.test1.UrlPageActivity">


            <WebView
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:id="@+id/url_page_web_view" />
        </RelativeLayout>

</android.support.v4.widget.SwipeRefreshLayout>
Hamid
quelle
0

Hier ist eine Methode, mit der Sie eine registrieren können Runnable, die ausgeführt werden soll, sobald eine bestimmte Webadresse vollständig geladen wurde. Wir verknüpfen jede Runnablemit einer entsprechenden URL Stringin a Mapund verwenden die Methode von WebView's getOriginalUrl(), um den entsprechenden Rückruf auszuwählen.

package io.github.cawfree.webviewcallback;

/**
 *  Created by Alex Thomas (@Cawfree), 30/03/2017.
 **/

import android.net.http.SslError;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.webkit.SslErrorHandler;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import java.util.HashMap;
import java.util.Map;

/** An Activity demonstrating how to introduce a callback mechanism into Android's WebView. */
public class MainActivity extends AppCompatActivity {

    /* Member Variables. */
    private WebView               mWebView;
    private Map<String, Runnable> mCallbackMap;

    /** Create the Activity. */
    @Override protected final void onCreate(final Bundle pSavedInstanceState) {
        // Initialize the parent definition.
        super.onCreate(pSavedInstanceState);
        // Set the Content View.
        this.setContentView(R.layout.activity_main);
        // Fetch the WebView.
        this.mWebView     = (WebView)this.findViewById(R.id.webView);
        this.mCallbackMap = new HashMap<>();
        // Define the custom WebClient. (Here I'm just suppressing security errors, since older Android devices struggle with TLS.)
        this.getWebView().setWebViewClient(new WebViewClient() {
            /** Handle when a request has been launched. */
            @Override public final void onPageFinished(final WebView pWebView, final String pUrl) {
                // Determine whether we're allowed to process the Runnable; if the page hadn't been redirected, or if we've finished redirection.
                if(pUrl.equals(pWebView.getOriginalUrl())) {
                    // Fetch the Runnable for the OriginalUrl.
                    final Runnable lRunnable = getCallbackMap().get(pWebView.getOriginalUrl());
                    // Is it valid?
                    if(lRunnable != null) { lRunnable.run(); }
                }
                // Handle as usual.
                super.onPageFinished(pWebView, pUrl);
            }
            /** Ensure we handle SSL state properly. */
            @Override public final void onReceivedSslError(final WebView pWebView, final SslErrorHandler pSslErrorHandler, final SslError pSslError) { pSslErrorHandler.proceed(); }
        });
        // Assert that we wish to visit Zonal's website.
        this.getWebView().loadUrl("http://www.zonal.co.uk/");
        // Align a Callback for Zonal; this will be serviced once the page has loaded.
        this.getCallbackMap().put("http://www.zonal.co.uk/", new Runnable() {     @Override public void run() { /* Do something. */ } });
    }

    /* Getters. */
    public final WebView getWebView() {
        return this.mWebView;
    }

    private final Map<String, Runnable> getCallbackMap() {
        return this.mCallbackMap;
    }

}
Mapsy
quelle
0

Der Renderer beendet das Rendern nicht, wenn die OnPageFinshed-Methode aufgerufen wird oder der Fortschritt 100% erreicht, sodass beide Methoden nicht garantieren, dass die Ansicht vollständig gerendert wurde.

Mit der OnLoadResource-Methode können Sie jedoch herausfinden, was bereits gerendert wurde und was noch gerendert wird. Und diese Methode wird mehrmals aufgerufen.

        @Override
        public void onLoadResource(WebView view, String url) {
            super.onLoadResource(view, url);
           // Log and see all the urls and know exactly what is being rendered and visible. If you wanna know when the entire page is completely rendered, find the last url from log and check it with if clause and implement your logic there.
            if (url.contains("assets/loginpage/img/ui/forms/")) {
                // loginpage is rendered and visible now.
               // your logic here.

            }
        }
Shreedhar
quelle
0

Verwenden Sie dies, es sollte helfen.`var currentUrl = "google.com" var partOfUrl = currentUrl.substring (0, currentUrl.length-2)

webView.setWebViewClient (Objekt: WebViewClient () {

override fun onLoadResource(WebView view, String url) {
     //call loadUrl() method  here 
     // also check if url contains partOfUrl, if not load it differently.
     if(url.contains(partOfUrl, true)) {
         //it should work if you reach inside this if scope.
     } else if(!(currentUrl.startWith("w", true))) {
         webView.loadurl("www.$currentUrl")

     } else if(!(currentUrl.startWith("h", true))) {
         webView.loadurl("https://$currentUrl")

     } else { ...}


 }

override fun onReceivedSslError(view: WebView?, handler: SslErrorHandler?, error: SslError?) {
   // you can call again loadUrl from here too if there is any error.
}

// Sie sollten auch andere Überschreibungsmethoden für Fehler wie onReceiveError überschreiben, um zu sehen, wie alle diese Methoden nacheinander aufgerufen werden und wie sie sich beim Debuggen mit Haltepunkt verhalten. } `

Jemand
quelle
-1

für Kotlin-Benutzer:

webView.webViewClient = object : WebViewClient() {
            override fun onPageFinished(view: WebView?, url: String?) {
                // do your logic
            }
        }

Es gibt jedoch viele Methoden, die Sie überschreiben können

Amin Keshavarzian
quelle