502

I have a WebView that is loading a page from the Internet. I want to show a ProgressBar until the loading is complete.

How do I listen for the completion of page loading of a WebView?

Sufian
  • 6,405
  • 16
  • 66
  • 120
Janusz
  • 187,060
  • 113
  • 301
  • 369
  • 1
    Please consider marking my answer as correct, as it solves some problems that ian's doesn't. – neteinstein Feb 10 '14 at 16:52
  • I think a better way to call the native java code with js when page loaded. [Refer this answer, though it's for ios, but the idea applys here too](https://stackoverflow.com/a/43672099/6521116). – LF00 Jul 06 '17 at 08:56
  • Anyone know how to do this with a MAUI WebView? – DevDave Jan 24 '22 at 16:00

18 Answers18

781

Extend WebViewClient and call onPageFinished() as follows:

mWebView.setWebViewClient(new WebViewClient() {

   public void onPageFinished(WebView view, String url) {
        // do your stuff here
    }
});
Taslim Oseni
  • 6,086
  • 10
  • 44
  • 69
ian
  • 15,686
  • 2
  • 22
  • 18
  • I have some issues with external loadings when the Internet is not so fast. For example Google Analytics or other stuffs like that. I tried some workarounds and it has improved a lot, but not perfect yet. Sometimes the app freeze on loading screen and it is impossible to exit, unless you disconnect the network or connect in another good one. I don't know how to solve this yet, I'm trying. – Felipe Jul 18 '11 at 00:10
  • @Felipe why don't you use something like this: http://stackoverflow.com/questions/4302912/android-webview-timeout – neteinstein Aug 25 '11 at 16:15
  • 1
    Works perfect. You can use mWebView.setVisibility(View.INVISIBLE) before loading. When load complete set it back to View.VISIBLE. I used it with this splash screen: http://android-developers.blogspot.de/2009/03/window-backgrounds-ui-speed.html – Johan Hoeksma Aug 25 '14 at 13:24
  • Sometimes, onPageFinished will be called even if the page is not rendered fully, So you may get a blank screen on webview . To show progress dialog untill the page is fully rendered you have to use onLoadResource and check the progress of the page. Check this answer http://stackoverflow.com/a/31537328/1066839 – John Jul 21 '15 at 11:08
  • 66
    This is not a solution at all. There is no guarantee the page is already loaded when this method is called. – Hawk Sep 23 '15 at 15:50
  • 4
    This is such a bad design on Google's part. Almost all the time when this action completes you want to do something oriented around the parent Activity, not the web view itself. Overriding a function instead of subscribing to an event is a common anti-pattern and reason I dislike android development. – Ryan Jul 28 '16 at 23:25
  • 3
    where is `@Override`? – user25 Sep 04 '16 at 13:40
  • 7
    This method does not guarantee the load finish and can be called more than once if the url load takes some intermediate url navigation. So this gets called multiple times . However its a way to check it. – beginner Jan 25 '17 at 06:15
  • I think a better way to call the native java code with js when page loaded. [Refer this answer, though it's for ios, but the idea applys here too](https://stackoverflow.com/a/43672099/6521116). – LF00 Jul 06 '17 at 08:56
  • @Hawk @beginner so what exactly does this guarantee? Can this at least guarantee `DOMContentLoaded` (DOM has been fully constructed)? – Maria Jul 13 '17 at 09:41
  • Check my answer below for an easier and guaranteed way, if its a loader you are displaying. – Skynet Apr 03 '20 at 17:51
169

@ian this is not 100% accurate. If you have several iframes in a page you will have multiple onPageFinished (and onPageStarted). And if you have several redirects it may also fail. This approach solves (almost) all the problems:

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

UPDATE:

According to the documentation: onPageStarted will NOT be called when the contents of an embedded frame changes, i.e. clicking a link whose target is an iframe.

I found a specific case like that on Twitter where only a pageFinished was called and messed the logic a bit. To solve that I added a scheduled task to remove loading after X seconds. This is not needed in all the other cases.

UPDATE 2:

Now with current Android WebView implementation:

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; 
            }
        }
    });
Community
  • 1
  • 1
neteinstein
  • 17,529
  • 11
  • 93
  • 123
  • 4
    You have probably noticed the caveat in onPageStarted's doc: onPageStarted will **NOT** be called when the contents of an embedded frame changes, i.e. clicking a link whose target is an iframe. So this may skew the logic in those cases. BTW, does @polen's simplification really work? – an00b Dec 09 '11 at 16:51
  • 1
    Nice catch, never noticed the frame stuff. I haven't tried the polen's code.. the only that i can assure that work's it's the above that i'm using. – neteinstein Jan 02 '12 at 15:04
  • 3
    Just a minor correction. It's actually "public void onPageStarted (WebView view, String url, Bitmap favicon)" instead of "public void onPageStarted(WebView view, String url)" – MrMaffen Jul 02 '14 at 15:38
  • Doesn't work for some of the newer sites that never finish loading...e.g., "agoda.com". You never get the onPageFinished call because it's a redirect. – kenyee Aug 24 '16 at 19:40
  • I have seen seen onPageFinished being called twice during a redirect. But, what you have said "If you have several iframes in a page you will have multiple onPageFinished (and onPageStarted)" is not right as per the documentation of onPageFinished: " This method is called only for main frame." – garnet Apr 04 '17 at 11:23
  • I know that the documentation has that, but.. it doesn't happen at least on all devices in that way. – neteinstein Apr 05 '17 at 13:58
42

I am pretty partial to @NeTeInStEiN (and @polen) solution but would have implemented it with a counter instead of multiple booleans or state watchers (just another flavor but I thought might share). It does have a JS nuance about it but I feel the logic is a little easier to understand.

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.
            }
        }
    });
}
Ben Pearson
  • 7,532
  • 4
  • 30
  • 50
SciSpear
  • 2,008
  • 18
  • 18
  • 2
    You code looks good. I have been trying the same for my webview which loads from html data not url. But this one triggers the onPageFinished if the first webview loads quickly and before the second one starts to load. Normal scenario. running =1 , running = 2, --running =1 , --running =0. Unusual scenario that fails - running =1 , --running = 0, running =1 running =0 – Ajith M A Mar 19 '14 at 07:04
  • 1
    There is also another scenario, when an event is not fired for some reason the TODO part will be never be reached. So you need a timer to check for timeouts. Or you can call an exported java function in javascript when you know everything is loaded properly. Something like documentReady() or something like that. – Codebeat Jun 14 '15 at 08:19
  • why not just `running = 1;` in `onPageStarted()` ? – Choletski Jul 14 '16 at 07:29
  • @Choletski Because the maximum of 1 and a number larger than 1 is not 1. – Matthew Read Mar 18 '18 at 09:04
41

I found one elegant solution as well, have not tested it rigorously though:

public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            if (webView.getProgress() == 100) {
                progressBar.setVisibility(View.GONE);
                webView.setVisibility(View.VISIBLE);
            }
        } 
Skynet
  • 7,820
  • 5
  • 44
  • 80
  • 3
    I have tested it and it is working perfectly, You can, of course, calling it from outside the onPageFinished method and use a Handler to check in short intervals - in cases, you don't want to extend the WebViewClient class. – Gal Rom Oct 31 '17 at 10:31
  • 1
    I believe this might be better than the accepted answer, you'd just need to check the onError and you're set. – Evin1_ Apr 10 '18 at 13:06
  • 1
    It is February 2023 and on my app, every time `onPageFinished()` is called, `webView.getProgress()` always returns 100 - even in the presence of redirects! Progress calculation must have changed since Jun 30, 2010 (timestamp of the accepted answer), because I recall struggling back then with the same issue, and [@neteinstein's answer](https://stackoverflow.com/a/5172952/2597758) was the only working solution back then. – WebViewer Feb 27 '23 at 20:34
24

If you want show a progress bar you need to listen for a progress change event, not just for the completion of page:

mWebView.setWebChromeClient(new WebChromeClient(){

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

                //change your progress bar
            }


        });

BTW if you want display just an Indeterminate ProgressBar overriding the method onPageFinished is enough

Francesco Laurita
  • 23,434
  • 8
  • 55
  • 63
23

I have simplified NeTeInStEiN's code to be like this:

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

        }
 });

It is easy to understand, OnPageFinished if the previous callback is on onPageStarted, so the page is completely loaded.

Community
  • 1
  • 1
polen
  • 639
  • 1
  • 8
  • 14
  • 3
    @polen PAGE_STARTED never gets cleared? What if shouldOverrideUrlLoading() never gets called? – an00b Dec 07 '11 at 22:20
8

for Kotlin users:

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

there are a lot of methods that you can override though

Amin Keshavarzian
  • 3,646
  • 1
  • 37
  • 38
7

Use setWebViewClient() and override onPageFinished()

Robby Pond
  • 73,164
  • 16
  • 126
  • 119
5

thanks for the answers. It helped me, but I had to improve it a bit for my needs. I had several pagestarts and finishes so I added a timer which checks if atfer the pagefinish is started a new pagestart. Okay, bad explanation. See the 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
  • 2,892
  • 1
  • 33
  • 32
5

You can trace the Progress Staus by the getProgress method in webview class.

Initialize the progress status

private int mProgressStatus = 0;

then the AsyncTask for loading like this:

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();
        }
    }
}
BenMorel
  • 34,448
  • 50
  • 182
  • 322
Praveen
  • 90,477
  • 74
  • 177
  • 219
4

Here's a novel method for detected when a URL has loaded by utilising Android's capability for JavaScript hooks. Using this pattern, we exploit JavaScript's knowledge of the document's state to generate a native method call within the Android runtime. These JavaScript-accessible calls can be made using the @JavaScriptInterface annotation.

This implementation requires that we call setJavaScriptEnabled(true) on the WebView's settings, so it might not be suitable depending on your application's requirements, e.g. security concerns.

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

Essentially, we're appending an additional JavaScript function that is used to test the state of the document. If it's loaded, we launch a custom onPageLoaded() event in Android's MainActivity; otherwise, we register an event listener that updates Android once the page is ready, using window.addEventListener('onload', ...);.

Since we're appending this script after the call to this.getWebView().loadURL("") has been made, it's probable that we don't need to 'listen' for the events at all, since we only get a chance to append the JavaScript hook by making a successive call to loadURL, once the page has already been loaded.

Mapsy
  • 4,192
  • 1
  • 37
  • 43
  • Awesome solution, which generally works. I am having problems with [https://reddit.com/r/Nature](https://reddit.com/r/Nature) (with Reddit generally), when you click on some thread and the thread is loaded, I am not able to catch that event. Can you help me out? – c0dehunter Dec 11 '18 at 11:03
  • @PrimožKralj Glad to hear you're having _some_ success with this... I'm not sure what to suggest specifically, but if there are any kind of public events which you know are triggered that you can hook into, for example when the comment count is updated, you can use that as a source. Have you considered that maybe your problem could be fixed by hitting Reddit's [API](https://www.reddit.com/dev/api/) directly? – Mapsy Dec 11 '18 at 16:04
  • 1
    Thanks, I'll have another look at the events triggered and try to hook to one of them. I am aware of the API, and will try to implement a more robust solution using it in the future. Thanks! – c0dehunter Dec 12 '18 at 09:07
  • `onload` didn't work for me, but I used `load` instead and then it worked perfectly! Thanks – 0101100101 Mar 02 '23 at 09:03
3

Just to show progress bar, "onPageStarted" and "onPageFinished" methods are enough; but if you want to have an "is_loading" flag (along with page redirects, ...), this methods may executed with non-sequencing, like "onPageStarted > onPageStarted > onPageFinished > onPageFinished" queue.

But with my short test (test it yourself.), "onProgressChanged" method values queue is "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);
    }
}

Also set "is_loading = false" on activity close, if it is a static variable because activity can be finished before page finish.

1

The renderer will not finish rendering when the OnPageFinshed method is called or the progress reaches 100% so both methods don't guarantee you that the view was completely rendered.

But you can figure out from OnLoadResource method what has been already rendered and what is still rendering. And this method gets called several times.

        @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
  • 41
  • 6
1

this will been called before he start loading the page (and get the same parameters as onFinished())

@Override
public void onPageCommitVisible(WebView view, String url) {
   super.onPageCommitVisible(view, url);
}
niek tuytel
  • 899
  • 7
  • 18
0

Loading url with SwipeRefreshLayout and 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
  • 1,493
  • 2
  • 18
  • 32
0

Here's a method which allows you to register a Runnable to be executed once a particular web address has finished loading. We associate each Runnable with a corresponding URL String in a Map, and we use the WebView's getOriginalUrl() method to choose the appropriate callback.

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
  • 4,192
  • 1
  • 37
  • 43
0

Use this it should help.`var currentUrl = "google.com" var partOfUrl = currentUrl.substring(0, currentUrl.length-2)

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

//You should also override other override method for error such as onReceiveError to see how all these methods are called one after another and how they behave while debugging with break point. } `

SomeOne
  • 31
  • 2
0

Kotlin solution First Solution is create webviewclient as private class and it is more efficient. In the other hand second soltion is sorter :)

First Solution

class MainActivity : AppCompatActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val webView : WebView = findViewById(R.id.webView)
    webView.webViewClient = MyWebViewClient()
 }

private class MyWebViewClient : WebViewClient() {
    override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
        println("Load Started")
    }
    override fun onPageFinished(view: WebView, url: String) {
        println("Load Finished")
    }
  }
}

Second Solution

class MainActivity : AppCompatActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val webView : WebView = findViewById(R.id.webView)
    webView.webViewClient = object : WebViewClient() {
        override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
            println("Load Started")
        }
        override fun onPageFinished(view: WebView, url: String) {
            println("Load Finished")
        }
     }
 }

Both solution actually same. So onPageStarted function run when page started to load in the other hang onPageFinished function works when page loaded entirely. You may want to write your as an example loadFinishedRun() function inside onPageFinished funtion.

Better late than never

Cemil AKAN
  • 68
  • 1
  • 3
  • Generally, answers are much more helpful if they include an explanation of what the code is intended to do, and why that solves the problem without introducing others. – DCCoder May 20 '21 at 17:07
  • That comment was posted from a review. And while your concern is appreciated if you have an issue with a comment it is best to flag it. It is also important that the [Code of Conduct](https://stackoverflow.com/conduct) is followed regardless of the content of a question, answer, or comment. – DCCoder May 21 '21 at 14:56