65

I'm trying to load in my WebView some HTML code that contains JavaScript.

Now , I want to test if my WebView is loaded before 5 secondes. I've tried the method getProgress(), but sometimes I get that the progress is 100, but my Webview is not loaded.
Is there another way to be sure that my Webview is loaded 100%?

This is a part of my code :

sdk.getWebView().loadDataWithBaseURL("notreal/", data_html,MIME_TYPE,ENCODING_UTF_8,null);

Timer timer = new Timer();
TimerTask task = new TimerTask() {

    @Override
    public void run(){                      
    Log.i("TAG", "progress fin = "+sdk.getWebView().getProgress());

    if(sdk.getWebView().getProgress() <100){
        //cancel the webView
        sdk.getContext().runOnUiThread(new Runnable() {
             @Override
             public void run() {
            sdk.getImgView().setVisibility(View.VISIBLE);
            sdk.getWebView().setVisibility(View.GONE);
             }
        });
    }

    // else ,the Webview is loaded
    else{
        //prepare webview 
        sdk.getContext().runOnUiThread(new Runnable() {
            @Override
            public void run(){
                     // hide imageView
                     sdk.getImgView().setVisibility(View.GONE);
                     sdk.getWebView().setVisibility(View.VISIBLE);
            }
        });
    }

 }
 };
 timer.schedule(task, 5000);
Adinia
  • 3,603
  • 5
  • 38
  • 56
Houcine
  • 22,593
  • 13
  • 53
  • 83
  • possible duplicate of [How to listen for a Webview finishing loading a URL in Android?](http://stackoverflow.com/questions/3149216/how-to-listen-for-a-webview-finishing-loading-a-url-in-android) – DroidDev Jun 13 '14 at 08:26

9 Answers9

90

As said here: How to listen for a WebView finishing loading a URL?

boolean loadingFinished = true;
boolean redirect = false;

mWebView.setWebViewClient(new WebViewClient() {

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

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

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

   @Override
   public void onPageFinished(WebView view, String url) {
       if(!redirect){
          loadingFinished = true;
       }

       if(loadingFinished && !redirect){
         //HIDE LOADING IT HAS FINISHED
       } else{
          redirect = false; 
       }

    }
});
Community
  • 1
  • 1
neteinstein
  • 16,975
  • 11
  • 87
  • 117
  • thanks for the reply , but i'm not loading an URL , i'm loading an HTML Code , you think that it will work for my case ? – Houcine Jun 01 '11 at 10:44
  • it gives me an error when i'm trying to override the method **`onPageStarted`** , and i'm using java Compiler 1.6 , android 1.6 ; any idea ??? – Houcine Jun 01 '11 at 11:04
  • 1
    ok i've fixed it , the prototype of the method is like this : `onPageStarted(WebView webview, String url,Bitmap favicon)` – Houcine Jun 01 '11 at 11:11
  • Don't know for sure...try :-) – neteinstein Jun 01 '11 at 12:36
  • 3
    It seems to be working though, thanks :), @Houcine: thanks for the thought, very useful. – Mark Joseph Del Rosario Aug 03 '12 at 09:32
  • 1
    Note that `onPageFinished` fires before any scripts with the `async` attribute set is done loading. So the page might not be _finished_ finished. – Nilzor Jul 24 '15 at 08:32
  • 6
    NOTE: this is *NOT* the same as "has webview rendered"...you'll still get a slight delay between getting the loaded and when it actually renders – kenyee Jul 31 '15 at 14:07
12

The best way to detect if a page has rendered is to use the onPageCommitVisible callback, available from API 23. onPageLoadFinished is not suitable, since it's delivered too soon (when the HTML is processed, but not yet rendered).

webview.setWebViewClient(new WebViewClient() {

    @Override
     public void onPageCommitVisible (WebView view, 
            String url)
    }
}
Daniel Novak
  • 2,590
  • 3
  • 25
  • 36
  • 2
    the best answer so far – injecteer Jan 15 '19 at 09:31
  • According to the linked doc, _It is called at the earliest point at which it can be guaranteed that WebView#onDraw will no longer draw any content from previous navigations. The next draw will display either the WebView#setBackgroundColor of the WebView, or some of the contents of the newly loaded page._ So, at the time that it's called, there's no guarantee that the page is fully loaded. – SpaceBison Feb 19 '20 at 11:26
  • I've been running some tests with a page that loads some content from JS and `onPageCommitVisible` were called before `onPageFinished`. Both of them were called before the page has been actually fully loaded. – SpaceBison Feb 19 '20 at 11:34
10
webView.setWebChromeClient(new WebChromeClient() {
            public void onProgressChanged(WebView view, int progress) {
                if (progress == 100) {
                    //do your task

                }
            }
        });
Rajesh Gauswami
  • 528
  • 6
  • 20
  • It works, and this is better than the using of the onPageFinished() of the WebViewClient. – Dario Brux Jun 27 '18 at 08:37
  • The question was " if my WebView is loaded..." onProgressChanged shows progress 100% even in case url failed (not downloaded). – mr.kostua Dec 11 '19 at 11:16
6

You need to overwrite the onPageFinished of WebViewClient

Here is an example for you

private class Callback extends WebViewClient {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        view.loadUrl(url);
        return true;
    }


    @Override
    public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);
        //do what you want to do

        }


}
Tanmay Mandal
  • 38,117
  • 12
  • 49
  • 46
4

You can try to extend WebChromeClient, override onProgressChanged(WebView view, int newProgress) and register it on your WebView with setWebChromeClient(WebChromeClient) method. This will free your application from the additional thread that you are starting just to check whether progress changed. Use the callback, it is simpler. So that would be the first thing.

Another one is that I was also experimenting with this progress status and I came to some conclusions about how it behaves:

  • for some use cases (such as check if page is even under the given url) it has to be greater then 10. When WebView makes the connection to the url provided then it automatically sets the progress value to 10 even if it did not make a successful connection, if it is greater then 10, then you can be sure that url could be accessed and the loading has begun,
  • progress will be returned as 100% when you call stopLoading() on your WebView,
  • keeping previous point in mind also when WebView won't be able to load the full site (it will get a timeout for an image for example) then it will report that page was fully loaded (100%)

To sum up, this progress bar is an indicator on whether WebView has finished loading the site or not but in terms of WebKit not in terms of page being completely downloaded. You have to keep in mind that connection may crash, resources (images, css, js) may not load for some reason, JavaScript can load some more resources when page will finish up loading etc. this progress can't tell you if the sites content was fully loaded or not, it tells you that WebView thinks that this should be all.

I have no other ideas on how to check whether page was fully loaded or not, I think this is the only way.

Hugo Gresse
  • 14,772
  • 8
  • 69
  • 103
Maciej Pigulski
  • 1,534
  • 12
  • 26
3

Set a WebChromeClient for WebView Another way to determine when page loading finish

            mWebView.setWebChromeClient(new WebChromeClient(){
                /*public void onProgressChanged (WebView view, int newProgress)           Tell the host application the current progress of loading a page.

                    Parameters
                        view WebView: The WebView that initiated the callback.

                        newProgress int: Current page loading progress, represented by an
                            integer between 0 and 100.
                */
                public void onProgressChanged(WebView view, int newProgress){
                    Toast.makeText(getActivity().getApplicationContext(),"Page loading : " + newProgress + "%",Toast.LENGTH_SHORT).show();

            if(newProgress == 100){
                // Page loading finish
                Toast.makeText(getActivity().getApplicationContext(),"Page loaded",Toast.LENGTH_SHORT).show();
            }
                }
            });
Shahbaz Ali
  • 885
  • 7
  • 13
2

Above solutions did not work for me, I wanted to make sure I have page loaded 100% and then inject javascript to do some intensive research on the page. I came up with following solution with little deviation from the solution provided by NeTeInStEiN. This may not work for everyone but it worked for me. Again it depends on what you are trying to achieve from the finished page.

String url; is from your activity which want to load this url
    private class ExtendedWebViewClient extends WebViewClient {
        private int webViewPreviousState;
        private final int PAGE_STARTED = 0x1;
        private final int PAGE_REDIRECTED = 0x2;
        public void onPageStarted(WebView paramWebView, String paramString,
                Bitmap paramBitmap) {
            super.onPageStarted(paramWebView, paramString, paramBitmap);
            if(paramString.contentEquals(url)) {
                webViewPreviousState = PAGE_STARTED;
            } else {
                webViewPreviousState = PAGE_REDIRECTED;
            }
// DO YOU STUFF IF NEEDED
}
        public void onPageFinished(WebView paramWebView, String paramString) {
            if (webViewPreviousState == PAGE_STARTED) {
// I AM GETTING HERE WHEN MY PAGE IS LOADED 100%
// NOW ITS TIME FOR ME TO RUN JAVASCRIPT FUNCTIONS
// DO YOUR STUFF
}
}

Hope This helps.

mask
  • 5,808
  • 3
  • 21
  • 22
1

The below code works perfectly. Once the page has been loaded successfully it will trigger onPageFinished()

        webView.setWebViewClient(new WebViewClient(){

        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            Toast.makeText(getApplicationContext(),"Started",Toast.LENGTH_SHORT).show();
            super.onPageStarted(view, url, favicon);
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            Toast.makeText(getApplicationContext(),"Loaded",Toast.LENGTH_SHORT).show();
            super.onPageFinished(view, url);
        }
    });
0

I also have a solution for that because already went through the condition where need to show webview after loading finish. Hope you guys understand it.

    webview.loadUrl(url)
    webview.webViewClient = object : WebViewClient() {

        override fun onPageCommitVisible(view: WebView?, url: String?) {
            webview.visibility = View.GONE
            // your method to call the css and load it into the existing webview
            loadCSS()
            super.onPageCommitVisible(view, url)
        }
        override fun onPageFinished(view: WebView?, url: String?) {
            super.onPageFinished(view, url)
            if (webview.progress == 100) {
                webview.visibility = View.VISIBLE
            }
            progressBar.visibility = View.GONE
        }
    }