Jak nasłuchiwać, jak WebView kończy ładowanie adresu URL?

447

Mam WebViewstronę ładującą stronę z Internetu. Chcę pokazywać, ProgressBaraż ładowanie się zakończy.

Jak słuchać zakończenia ładowania strony WebView?

Janusz
źródło
1
Proszę rozważyć zaznaczenie mojej odpowiedzi jako poprawnej, ponieważ rozwiązuje ona niektóre problemy, których nie rozwiązuje Ian.
neteinstein
Myślę, że lepszy sposób na wywołanie natywnego kodu Java za pomocą js po załadowaniu strony. Odnieś się do tej odpowiedzi, chociaż dotyczy to iOS, ale pomysł dotyczy również tutaj .
Kris Roofe,
Sprawdź moją odpowiedź poniżej, aby uzyskać minimalne i zwięzłe rozwiązanie
Skynet

Odpowiedzi:

716

Rozszerz WebViewClient i wywołaj onPageFinished () w następujący sposób:

mWebView.setWebViewClient(new WebViewClient() {

   public void onPageFinished(WebView view, String url) {
        // do your stuff here
    }
});
Ian
źródło
Mam pewne problemy z ładowaniem zewnętrznym, gdy Internet nie jest tak szybki. Na przykład Google Analytics lub inne podobne rzeczy. Wypróbowałem kilka obejść i wiele się poprawiło, ale jeszcze nie jest idealne. Czasami aplikacja zawiesza się na ekranie ładowania i nie można wyjść, chyba że odłączysz sieć lub podłączysz inną dobrą. Nie wiem jeszcze, jak to rozwiązać, próbuję.
Felipe
1
Działa idealnie. Możesz użyć mWebView.setVisibility (View.INVISIBLE) przed załadowaniem. Po zakończeniu ładowania ustaw go ponownie w View.VISIBLE. Użyłem go z tym ekranem powitalnym: android-developers.blogspot.de/2009/03/…
Johan Hoeksma
39
To wcale nie jest rozwiązanie. Nie ma gwarancji, że strona jest już załadowana, gdy wywoływana jest ta metoda.
Hawk,
3
To taki zły projekt ze strony Google. Prawie cały czas po zakończeniu tej akcji chcesz zrobić coś ukierunkowanego wokół działania nadrzędnego, a nie samego widoku internetowego. Zastępowanie funkcji zamiast subskrybowania wydarzenia jest powszechnym anty-wzorcem i powodem, dla którego nie lubię programowania Androida.
Ryan
6
Ta metoda nie gwarantuje zakończenia ładowania i może być wywołana więcej niż jeden raz, jeśli ładowanie adresu URL wymaga pośredniej nawigacji adresu URL. Jest to wywoływane wiele razy. Jest to jednak sposób na sprawdzenie tego.
początkujący
150

@ian nie jest to w 100% dokładne. Jeśli masz kilka ramek iframe na stronie, będziesz mieć wiele onPageFinished (i onPageStarted). A jeśli masz kilka przekierowań, może również nie powieść się. To podejście rozwiązuje (prawie) wszystkie problemy:

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

AKTUALIZACJA:

Zgodnie z dokumentacją: onPageStarted NIE zostanie wywołany, gdy zmieni się zawartość osadzonej ramki, tj. Kliknięcie łącza, którego celem jest element iframe.

Znalazłem taki konkretny przypadek na Twitterze, gdzie wywołano tylko stronęFinished i trochę popsułem logikę. Aby rozwiązać ten problem, dodałem zaplanowane zadanie usuwania ładowania po X sekundach. Nie jest to konieczne we wszystkich innych przypadkach.

AKTUALIZACJA 2 :

Teraz z aktualną implementacją Android WebView:

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
źródło
3
Prawdopodobnie zauważyłeś zastrzeżenie w dokumencie onPageStarted: onPageStarted NIE zostanie wywołany, gdy zmieni się zawartość osadzonej ramki, tj. Kliknięcie łącza, którego celem jest element iframe. W takich przypadkach może to wypaczyć logikę. BTW, czy uproszczenie @ polen naprawdę działa?
an00b
1
Niezły chwyt, nigdy nie zauważyłem rzeczy na ramce. Nie próbowałem kodu polen .. jedyne, co mogę zapewnić, że praca to powyższe, którego używam.
neteinstein
3
Drobna korekta. To rzeczywiście "public void onPageStarted (zobacz WebView, url String, favicon bitmapy)" zamiast "public void onPageStarted (zobacz WebView, String url)"
MrMaffen
Nie działa w przypadku niektórych nowszych witryn, które nigdy nie kończą się ładować ... np. „Agoda.com”. Nigdy nie otrzymasz połączenia onPageFinished, ponieważ jest to przekierowanie.
kenyee
Widziałem, że onPageFinished był wywoływany dwukrotnie podczas przekierowania. Ale to, co powiedziałeś „Jeśli masz kilka ramek iframe na stronie, będziesz mieć wiele elementów onPageFinished (i onPageStarted)” nie jest poprawne, zgodnie z dokumentacją onPageFinished: „Ta metoda jest wywoływana tylko dla ramki głównej”.
granat
40

Jestem dość stronniczy w stosunku do rozwiązania @NeTeInStEiN (i @polen), ale zaimplementowałbym go z licznikiem zamiast wielu boolanów lub obserwatorów stanu (tylko inny smak, ale myślałem, że mogę się nim podzielić). Ma w sobie niuans JS, ale myślę, że logika jest nieco łatwiejsza do zrozumienia.

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
źródło
2
Twój kod wygląda dobrze. Próbowałem tego samego dla mojego widoku internetowego, który ładuje z danych HTML, a nie URL. Ale ten wyzwala funkcję onPageFinished, jeśli pierwszy widok strony ładuje się szybko i zanim drugi zaczyna się ładować. Normalny scenariusz. running = 1, running = 2, --running = 1, --running = 0. Niezwykły scenariusz, który kończy się niepowodzeniem - bieg = 1, - bieg = 0, bieg = 1 bieg = 0
Ajith Memana
1
Istnieje również inny scenariusz, gdy z jakiegoś powodu nie zostanie uruchomione zdarzenie, część DO ZROBIENIA nigdy nie zostanie osiągnięta. Potrzebujesz timera, aby sprawdzić limity czasu. Lub możesz wywołać wyeksportowaną funkcję Java w javascript, jeśli wiesz, że wszystko zostało poprawnie załadowane. Coś jak documentReady () lub coś takiego.
Codebeat
dlaczego nie tylko running = 1;w onPageStarted()?
Choletski
@Choletski Ponieważ maksimum 1 i liczba większa od 1 nie jest równa 1.
Mateusz
25

Znalazłem też jedno eleganckie rozwiązanie, ale nie przetestowałem go rygorystycznie:

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
źródło
2
Przetestowałem to i działa idealnie. Możesz oczywiście wywołać go spoza metody onPageFinished i użyć modułu obsługi do sprawdzania w krótkich odstępach czasu - w niektórych przypadkach nie chcesz rozszerzać klasy WebViewClient.
Gal Rom
1
Wierzę, że może to być lepsze niż zaakceptowana odpowiedź, wystarczy sprawdzić onError i gotowe.
Evin1_
1
To powinna być zaakceptowana odpowiedź.
زياد
1
Głosuj za tym
Khdkls
23

Upraszczam kod NeTeInStEiN , aby był taki:

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

        }
 });

Łatwo to zrozumieć, OnPageFinished, jeśli poprzednie wywołanie zwrotne jest włączone naPageStarted, więc strona jest całkowicie załadowana.

polen
źródło
3
@polen PAGE_STARTED nigdy nie zostanie wyczyszczony? Co zrobić, jeśli powinien zostać wywołany powinienOverrideUrlLoading ()?
an00b
20

Jeśli chcesz pokazać pasek postępu, musisz nasłuchiwać zdarzenia zmiany postępu, a nie tylko ukończenia strony:

mWebView.setWebChromeClient(new WebChromeClient(){

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

                //change your progress bar
            }


        });

BTW, jeśli chcesz wyświetlić tylko nieokreślony pasek postępu przesłaniający metodę onPageFinished, wystarczy

Francesco Laurita
źródło
5

Możesz śledzić postępów Staus przez getProgress metody w Webview klasie.

Zainicjuj status postępu

private int mProgressStatus = 0;

następnie AsyncTask do ładowania w ten sposób:

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
źródło
mProgressStatus = webview.getProgress (); musi zostać wywołany z wątku interfejsu użytkownika.
Skynet,
5

dzięki za odpowiedzi. Pomogło mi to, ale musiałem to trochę poprawić dla moich potrzeb. Miałem kilka stron próbnych i zakończeń, więc dodałem licznik czasu, który sprawdza, czy po ukończeniu strony rozpoczyna się nowa strona próbna. Okej, złe wyjaśnienie. Zobacz kod :)

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
źródło
2

Oto nowatorska metoda wykrywania po załadowaniu adresu URL przy użyciu funkcji Androida do przechwytywania skryptów JavaScript . Korzystając z tego wzorca, wykorzystujemy wiedzę JavaScript o stanie dokumentu do generowania natywnego wywołania metody w środowisku wykonawczym Androida. Te wywołania dostępne w JavaScript można wykonywać za pomocą @JavaScriptInterfaceadnotacji.

Ta implementacja wymaga, którą nazywamy setJavaScriptEnabled(true)w WebViewustawieniach „s, więc to nie może być odpowiednie w zależności od wymagań Twojej aplikacji, np względów bezpieczeństwa.

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"
/>

Zasadniczo dodajemy dodatkową funkcję JavaScript, która służy do testowania stanu dokumentu. Jeśli jest załadowany, uruchamiamy niestandardowyonPageLoaded() wydarzenie w systemie Android MainActivity; w przeciwnym razie rejestrujemy detektor zdarzeń, który aktualizuje system Android, gdy strona jest gotowa, używając window.addEventListener('onload', ...);.

Ponieważ dołączamy ten skrypt po nawiązaniu połączenia this.getWebView().loadURL(""), jest prawdopodobne, że wcale nie musimy „nasłuchiwać” wydarzeń, ponieważ mamy szansę dołączyć haczyk JavaScript, wykonując kolejne wywołanie loadURL, po załadowaniu strony.

Mapsy
źródło
Niesamowite rozwiązanie, które ogólnie działa. Mam problemy z https://reddit.com/r/Nature (ogólnie z Reddit), kiedy klikniesz jakiś wątek i wątek jest załadowany, nie jestem w stanie złapać tego zdarzenia. Czy możesz mi pomóc?
Primož Kralj
@ PrimožKralj Cieszę się, że masz z tym jakiś sukces ... Nie jestem pewien, co konkretnie zasugerować, ale jeśli istnieją jakieś wydarzenia publiczne, o których wiesz, że są uruchamiane, na które możesz się przyłączyć, na przykład gdy liczba komentarzy jest aktualizowana, możesz użyć tego jako źródła. Czy zastanawiałeś się, że może Twój problem można rozwiązać, dotykając bezpośrednio interfejsu API Reddit ?
Mapsy
1
Dzięki, jeszcze raz przyjrzę się wyzwalanym wydarzeniom i spróbuję połączyć się z jednym z nich. Znam interfejs API i w przyszłości spróbuję zaimplementować bardziej niezawodne rozwiązanie. Dzięki!
Primož Kralj,
1

Aby wyświetlić pasek postępu, wystarczą metody „onPageStarted” i „onPageFinished”; ale jeśli chcesz mieć flagę „is_loading” (wraz z przekierowaniami strony, ...), metody te mogą być wykonywane bez sekwencjonowania, takie jak kolejka „onPageStarted> onPageStarted> onPageFinished> onPageFinished”.

Ale w moim krótkim teście (przetestuj sam.) Kolejka wartości metod „onProgressChanged” to „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);
    }
}

Ustaw także „ is_loading = false” przy zamknięciu działania, jeśli jest to zmienna statyczna, ponieważ działanie można zakończyć przed zakończeniem strony.

Jalil Hamdollahi Oskouei
źródło
0

Ładowanie SwipeRefreshLayoutProgressBaradresu URL za pomocą i :

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
źródło
0

Oto metoda, która umożliwia zarejestrowanie Runnabledo wykonania po zakończeniu ładowania określonego adresu internetowego. Kojarzy nam się każdy Runnablez odpowiednim adresem URL Stringw miłym Mapi używamy WebView„s getOriginalUrl()metody, aby wybrać odpowiedni zwrotnego.

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
źródło
0

Mechanizm renderujący nie zakończy renderowania, gdy zostanie wywołana metoda OnPageFinshed lub postęp osiągnie 100%, więc obie metody nie gwarantują całkowitego renderowania widoku.

Ale z metody OnLoadResource można dowiedzieć się, co zostało już wyrenderowane, a co nadal renderowane. I ta metoda jest wywoływana kilka razy.

        @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
źródło
0

Użyj tego, co powinno pomóc .var currentUrl = "google.com" var partOfUrl = currentUrl.substring (0, currentUrl.length-2)

webView.setWebViewClient (obiekt: 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.
}

// Powinieneś również przesłonić inną metodę zastępowania błędów, taką jak onReceiveError, aby zobaczyć, jak wszystkie te metody są wywoływane jedna po drugiej i jak zachowują się podczas debugowania z punktem przerwania. } `

Ktoś
źródło
-1

dla użytkowników Kotlin:

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

istnieje jednak wiele metod, które można zastąpić

Amin Keshavarzian
źródło