Friday, May 18, 2012

How to listen for a Webview finishing loading a URL in Android?


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 ?


Source: Tips4all

6 comments:

  1. Just implement WebViewClient and extend onPageFinished() as follows:

    mWebView.setWebViewClient(new WebViewClient() {

    public void onPageFinished(WebView view, String url) {
    // do your stuff here
    }
    });

    ReplyDelete
  2. @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;
    }

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

    }
    });


    UPDATE:
    I found a specific case on Twitter redirects where (i haven't found out yet why) 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 99% of cases.

    ReplyDelete
  3. 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 previouse callBack is onPageStarted, so the page is completely loaded.

    ReplyDelete
  4. 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

    ReplyDelete
  5. Use setWebViewClient() and override onPageFinished()

    ReplyDelete
  6. You can trace the Progress Staus by the getProgress mehtod 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();
    }
    }
    }

    ReplyDelete