6

I need to access the progress value in WebView -> WebChromeClient -> onProgressChanged(). The progress integer value doesn't increment from 0 to 100 but rather jumps around. Here is a sample log-output from loading one page and the associated progress numbers:

DEBUG:  progress : 10
DEBUG:  progress : 100
DEBUG:  progress : 10
DEBUG:  progress : 100
DEBUG:  progress : 10
DEBUG:  progress : 100
DEBUG:  progress : 10
DEBUG:  progress : 10
DEBUG:  progress : 100
DEBUG:  progress : 10
DEBUG:  progress : 100
DEBUG:  progress : 10
DEBUG:  progress : 100
DEBUG:  progress : 10
DEBUG:  progress : 100
DEBUG:  progress : 10
DEBUG:  progress : 30
DEBUG:  progress : 100
DEBUG:  progress : 10
DEBUG:  progress : 30
DEBUG:  progress : 100
DEBUG:  progress : 10
DEBUG:  progress : 30
DEBUG:  progress : 37
DEBUG:  progress : 45
DEBUG:  progress : 48
DEBUG:  progress : 49
DEBUG:  progress : 50
DEBUG:  progress : 52
DEBUG:  progress : 54
DEBUG:  progress : 56
DEBUG:  progress : 59
DEBUG:  progress : 61
DEBUG:  progress : 63
DEBUG:  progress : 66
DEBUG:  progress : 68
DEBUG:  progress : 70
DEBUG:  progress : 73
DEBUG:  progress : 75
DEBUG:  progress : 77
DEBUG:  progress : 79
DEBUG:  progress : 82
DEBUG:  progress : 84
DEBUG:  progress : 86
DEBUG:  progress : 87
DEBUG:  progress : 88
DEBUG:  progress : 89
DEBUG:  progress : 100

What am I doing wrong?

Code:

webView.setWebChromeClient(new WebChromeClient() {
    public void onProgressChanged(WebView view, int progress) {
        Log.i(LOG_TAG, "DEBUG: progress : " + progress);
    }
});
tamsler
  • 1,275
  • 1
  • 18
  • 26
  • 3
    What URL are you loading? Is it possible you are seeing redirects? Looks like the results are always monotonic in the range 0-100, but they are restarting. What version of android are you using? – ksasq Mar 06 '14 at 00:31
  • @ksasq You are right, there were numerous redirects and thus the progress got reset. Thank you. – tamsler Mar 06 '14 at 18:47

4 Answers4

5

From my own experiments, I found that onProgressChanged can get called multiple times for the same url for the same progress value (Ex: google.com progress = 100 calls twice).

I also found that onProgressChanged will be called late for a url while you are loading another one. Timetable example:

  1. Load google.com
  2. ProgressChanged = 100, webView.geturl(): google.com
  3. Load amazon.com
  4. ProgressChanged = 40, webView.getUrl(): amazon.com
  5. ProgressChanged = 100, webView.getUrl(): google.com

At this point, I should mention that in my experiments I override shouldOverrideUrlLoading() to see redirects and even when I don't see redirects the above still happens. So why does this happen?

According to this answer( Why is there a noticeable delay between WebChromeClient.onProgressChanged and jquery's $(document).ready() callbacks?): because a page is loaded before the script are triggered, document ready looks for all html elements to be loaded first except images and things like that, so your script does not fire until everything has been loaded, by that time your onprogresschanged has received 100% first as it may be have a higher priority than your javascript after all devices do ask to check if js should be allowed or not so it has to go through some checks before this method is called.

So to put it all together this is what you need to do:

  1. Don't trust onProgressChanged().
  2. onPageStarted() check that the current url you are trying to load matches webView.getUrl(). This is your starting point. Set a boolean finishedLoading to false.
  3. Assume your page is loaded when onPageFinished is called and webView.getUrl() matches the url you are trying to load. If no redirects, then set finishedLoading flag to true. However, for redirects, you will need to follow step 3.
  4. override shouldOverrideurlLoading(). Load the new url if it doesn't match the one that was originally loaded (webView.loadUrl(new redirect url)) and set finishedLoading to false.

Code

    private boolean isCurrentUrl(String url){
        return url.toLowerCase().contains(currentUrl.toLowerCase());
    }

   public void onPageStarted(WebView webView, String url,     
       android.graphics.Bitmap bitmap){

                if (isCurrentUrl(url)){
                    pageLoaded = false;
                }
   }

   public void onPageFinished(WebView webview, String url){
       if (isCurrentUrl(url)){
           pageLoaded = true;
       }
   }

   public boolean shouldOverrideUrlLoading(WebView view, String 
       url){
       if (!currentUrl.equalsIgnoreCase(url)){
           currentUrl = url;
           view.loadUrl(currentUrl);
           return true;
       }
       return false;
   }
Community
  • 1
  • 1
Juan Acevedo
  • 1,768
  • 2
  • 20
  • 39
2

As @ksasq pointed out in the above comment, the initial URL caused many redirects and thus onProgressChanged() is called many times.

tamsler
  • 1,275
  • 1
  • 18
  • 26
2

Best solution is to use the progress of webview and not progress(integer value from method onProgressChanged(WebView view, int progress))

psuedo code,

@Override
public void onProgressChanged(WebView view, int progress) {
       progressBar.setProgress(yourWebView.getProgress());
}

This solution works fine in all cases!

Lalit Poptani
  • 67,150
  • 23
  • 161
  • 242
0

There are two progress of webView. webView.getProgress() gives more accurate progress including progress of media files. onProgressChanged() progress gives relative progress according to visibility of the page. Below code works fine for me. Here I am using my custom webView.

import android.content.Context
import android.os.Build
import android.util.AttributeSet
import android.webkit.WebChromeClient
import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import com.xyz.interfaces.WebViewLoadingProgressListener


class MyWebView : WebView {

    private var webViewLoadingProgressListener: WebViewLoadingProgressListener? = null

    /**
     * to avoid webView progress inconsistency
     * and to get progress in incremental order
     */
    private var loadProgressCounter: Int? = null

    constructor(context: Context) : super(context) {
        initView(context)
    }

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
        initView(context)
    }

    fun setWebViewLoadingProgressListener(webViewLoadingProgressListener: WebViewLoadingProgressListener) {
        this.webViewLoadingProgressListener = webViewLoadingProgressListener
    }

    var totalContentHeight = 0

    private fun initView(context: Context) {
        this.settings.javaScriptEnabled = true
        this.settings.domStorageEnabled = true
        this.settings.setAppCacheEnabled(true)
        this.settings.loadsImagesAutomatically = true
        this.settings.loadWithOverviewMode = true
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            this.settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
        }


        this.webViewClient = object : WebViewClient() {
            /**
             * to restrict use of external browsing
             */
            override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
                view?.loadUrl(url)
                /**
                 * resetting on page change
                 */
                loadProgressCounter = null
                return true
            }
        }

        this.webChromeClient = object : WebChromeClient() {
            override fun onProgressChanged(view: WebView?, newProgress: Int) {
                /**
                 * use webView.getProgress() for more precise progress
                 */

                /**
                 * allowing incremental progress only
                 */
                if (loadProgressCounter == null || loadProgressCounter!! <= newProgress) {
                    loadProgressCounter = newProgress
                }
                /**
                 * sends progress to required class
                 */
                webViewLoadingProgressListener?.onProgressChange(loadProgressCounter!!)
            }
        }
    }


} 
Shahbaz Hashmi
  • 2,631
  • 2
  • 26
  • 49