28

I want to know how to determine when a WebView is completely done loading.

Let me define completely.

  • All redirects have happened
  • The page is visibly displayed, nothing has yet to load

Bad answers to this question:

WebViewClient.onPageFinished() - this fires multiple times if there are redirects loading a page. It also fires before the page is displayed.

PictureListener.onNewPicture() - this fires every time the screen changes and AFAICT each redirect. How would I know which firing is the final one?

WebChromeClient.onProgressChanged() - same problem as onPageFinished. (Added after David suggested this solution below)

Thread.sleep(5000) - should be obvious, why this isn't acceptable.

Of course, a clever combination of the above that works would be perfect.

Why do I want to know this you ask? Because I want to inject some javascript one time once the webview is completely done loading.

Carlos Rendon
  • 6,174
  • 5
  • 34
  • 50
  • 1
    Adding to your `WebViewClient.onPageFinished()` "bad answer": According to [this](http://stackoverflow.com/a/5172952/725417), it will fire multiple times **also** if you have several iframes in a page. – uTubeFan Dec 14 '11 at 00:50
  • @Carlos Man am in the exact same position as you were. The only thing thats makes my situation worse is that PictureListener is deprecated. Were you able to come up with a solution ? I have to calculate the total number of pages in the webview for which I need to divide the content width with the width of the screen. But I cannot do that until the page is completely rendered on the screen. Any solutions ? – Arunavh Krishnan Sep 23 '14 at 20:15
  • @ArunavhKrishnan Well last time I looked at this was 3 years ago. In the end I think I did something similar to the accepted answer. Good luck! – Carlos Rendon Sep 24 '14 at 22:26
  • 1
    Instead of injecting JavaScript once the page is done loading, you can use a Immediately-Invoked Function Expression (IIFE) or add a event listener that listens for the DOM ready event. There are `DOMContentLoaded` as well as `window.onload` and `document.ready`. – Fred Oct 28 '15 at 21:41

2 Answers2

9

Thanks to David Caunt for his suggestion to look at the response headers.

I've found the following to work pretty well:

Instead of having webview perform the HTTP requests, do them yourself so you can check the HTTP status code for redirects. Follow the redirection chain. When you get to a request that is not a redirect set a flag and send the data to the webview via webview.loadDataWithBaseURL. The flag is checked in WebViewClient.onPageFinished() so it knows that all redirects are done. The javascript can be injected at this point. Of course the page itself might be doing some javascript manipulation at this point, it is difficult to know, so adding a delay (say 500ms) to the javascript allows for the DOM to settle. setTimeout(function(){/* your code */}, 500).

Carlos Rendon
  • 6,174
  • 5
  • 34
  • 50
  • 1
    Useful to know! As for the page's own javascript, difficult to detect when that has finished. – David Snabel-Caunt Apr 21 '11 at 10:36
  • 1
    @Carlos Rendon +1 for a great outline. I am amazed that this isn't implemented in WebView or any of its satellite interfaces. This feature is so much needed, yet the only thing the WebView folks have been able to do is deprecate PictureListener. Any idea why? – uTubeFan Dec 12 '11 at 03:56
  • 1
    And while at that, it turns out that I am not the only one dreaming about [accessing the http response headers in a WebView](http://stackoverflow.com/questions/3134389/access-the-http-response-headers-in-a-webview). – uTubeFan Dec 12 '11 at 04:37
  • What about a **client-side** redirect? How would you catch it in the HTTP status code if it is empty by definition? – WebViewer Feb 27 '23 at 11:14
1

Have you looked at setting your own WebChromeClient?

It looks like onProgressUpdated might inform you when a page has fully loaded.

This appears to be the method used by Android's built-in browser.

David Snabel-Caunt
  • 57,804
  • 13
  • 114
  • 132
  • Thanks for the suggestion. Unfortunatley, this has the same problem as WebViewClient.onPageFinished(), it fires several times due to redirects. For example on "gmail.com" it fires 3 times with progress == 100. – Carlos Rendon Apr 07 '11 at 22:42
  • 1
    When does the next 0 value for progress come in? If it fires straight after a response issues a redirect, it may be safe to use a timeout and assume that you're on the last request. Otherwise, I'd be looking for a way to get response headers or somthing similar. – David Snabel-Caunt Apr 07 '11 at 22:44