59

In my application, I have a WebView which loads any URL from the internet. Now, sometimes due to slow networks the page takes a long time to load and the user sees only a blank screen.

I want to show a ProgressBar while the WebView gets loaded and hide the ProgessBar when the WebView gets loaded completely.

I know how to use the ProgressBar and AsyncTasks, but here is my problem.

This is the code that I use to load my WebView.

    mWebView = (WebView) findViewById(R.id.webview);
    mWebView.getSettings().setJavaScriptEnabled(true);
    mWebView.setWebViewClient(new HelloWebViewClient());
    mWebView.loadUrl(web_URL);

And this my custom WebViewClient class

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

Now, if I try to show the ProgressBar using AsyncTasks then I guess I would have to give the code to load the URL in the doInBackGround() function of my AsyncTask and show the progress through the onProgressUpdate() function.

But, how do I load the URL inside the doInBackground() as doInBackground() runs on the Non-UI thread and I wont be able to use mWebView.loadUrl(web_URL) inside it.

Any suggestions? Am I missing something obvious? Please guide me.

SpaceCore186
  • 586
  • 1
  • 8
  • 22
Swayam
  • 16,294
  • 14
  • 64
  • 102

12 Answers12

78

Check the source code. Help you and solve your problem...

public class AppWebViewClients extends WebViewClient {
     private ProgressBar progressBar;

    public AppWebViewClients(ProgressBar progressBar) {
        this.progressBar=progressBar;
        progressBar.setVisibility(View.VISIBLE);
    }
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        // TODO Auto-generated method stub
        view.loadUrl(url);
        return true;
    }

    @Override
    public void onPageFinished(WebView view, String url) {
        // TODO Auto-generated method stub
        super.onPageFinished(view, url);
        progressBar.setVisibility(View.GONE);
    }
}

I think it help you.

Thanks.

Md Abdul Gafur
  • 6,213
  • 2
  • 27
  • 37
  • 3
    Why does the method `shouldOverrideUrlLoading` need to be called? – winklerrr May 03 '17 at 15:37
  • 1
    shouldOverrideUrlLoading is deprecated now: The N Developer Preview has this method signature: public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) – Agna JirKon Rx Oct 26 '17 at 12:37
  • Thanx..it worked like a charm so one thumbs up for you! – brijexecon Jul 12 '18 at 11:16
  • @winklerrr, To keep page navigation within the WebView and hence within the app, we need to create a subclass of WebViewClient, and override its shouldOverrideUrlLoading(WebView webView, String url) method. – amoljdv06 Dec 16 '19 at 10:16
  • the [docs](https://developer.android.com/reference/android/webkit/WebViewClient#shouldOverrideUrlLoading(android.webkit.WebView,%20android.webkit.WebResourceRequest)) for both the deprecated method that you mention as well as the newer version, specifically says `Do not call WebView#loadUrl(String) with the request's URL and then return true. This unnecessarily cancels the current load and starts a new load with the same URL. The correct way to continue loading a given URL is to simply return false, without calling WebView#loadUrl(String)` – MoralCode May 08 '20 at 20:10
19

pass your url in this method

private void startWebView(String url) {

            WebSettings settings = webView.getSettings();

            settings.setJavaScriptEnabled(true);
            webView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY);

            webView.getSettings().setBuiltInZoomControls(true);
            webView.getSettings().setUseWideViewPort(true);
            webView.getSettings().setLoadWithOverviewMode(true);

            progressDialog = new ProgressDialog(ContestActivity.this);
            progressDialog.setMessage("Loading...");
            progressDialog.show();

            webView.setWebViewClient(new WebViewClient() {
                @Override
                public boolean shouldOverrideUrlLoading(WebView view, String url) {
                    view.loadUrl(url);
                    return true;
                }

                @Override
                public void onPageFinished(WebView view, String url) {
                    if (progressDialog.isShowing()) {
                        progressDialog.dismiss();
                    }
                }

                @Override
                public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
                    Toast.makeText(ContestActivity.this, "Error:" + description, Toast.LENGTH_SHORT).show();

                }
            });
            webView.loadUrl(url);
        }
Ishant Garg
  • 829
  • 9
  • 6
11

if you want to show the progressbar every time the user loads page (and not only the first load), then you can use this:

MainActivity.java

public class MainActivity extends Activity
{
    private WebView webView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        webView = (WebView) findViewById(R.id.webView);

        final ProgressDialog progressBar = new ProgressDialog(MainActivity.this);
        progressBar.setMessage("Please wait...");

        webView.loadUrl("https://example.org/");
        webView.setWebViewClient(new WebViewClient() {
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                view.loadUrl(url);
                return true;
            }

            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
                if (!progressBar.isShowing()) {
                    progressBar.show();
                }
            }

            public void onPageFinished(WebView view, String url) {
                if (progressBar.isShowing()) {
                    progressBar.dismiss();
                }
            }

            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
                if (progressBar.isShowing()) {
                    progressBar.dismiss();
                }
            }
        });

    }
}

activity_main.xml :

<?xml version="1.0" encoding="utf-8"?>
<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"
    android:paddingBottom="0dp"
    android:paddingLeft="0dp"
    android:paddingRight="0dp"
    android:paddingTop="0dp"
    tools:showIn="@layout/activity_main">

    <WebView
        android:id="@+id/webView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentEnd="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true" />

</RelativeLayout>
medskill
  • 320
  • 3
  • 13
10
  1. Using WebChromeClient:

    webView.webChromeClient = object: WebChromeClient() {
        override fun onProgressChanged(view: WebView?, newProgress: Int) {
            super.onProgressChanged(view, newProgress)
    
            progressBar?.isVisible = newProgress < 100
            progressBar?.progress = newProgress
        }
    }
    

In this case you can even show determined progress bar.

  1. Using WebViewClient:

     String url = "https://stackoverflow.com/questions/11241513/android-progessbar-while-loading-webview";
     setProgressBarVisibility(View.VISIBLE);
    
     webView.setWebViewClient(new WebViewClient() {
         @Override
         public void onPageStarted(WebView view, String url, Bitmap favicon) {
             super.onPageStarted(view, url, favicon);
             setProgressBarVisibility(View.VISIBLE);
         }
    
         @Override
         public void onPageFinished(WebView view, String url) {
             super.onPageFinished(view, url);
             setProgressBarVisibility(View.GONE);
         }
    
         @Override
         public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
             super.onReceivedError(view, request, error);
             setProgressBarVisibility(View.GONE);
         }
     });
    
     webView.loadUrl(url);
    

Also add method:

    private void setProgressBarVisibility(int visibility) {
        // If a user returns back, a NPE may occur if WebView is still loading a page and then tries to hide a ProgressBar.
        if (progressBar != null) {
            progressBar.setVisibility(visibility);
        }
    }
CoolMind
  • 26,736
  • 15
  • 188
  • 224
3
  @SuppressLint("SetJavaScriptEnabled")
private void init() {
    webView = (WebView) findViewById(R.id.kamal);
    webView.setBackgroundColor(0);
    webView.getSettings().setJavaScriptEnabled(true);
    progressDialog = new ProgressDialog(WebView_Ofline.this);
    progressDialog.setMessage("Loading Please wait...");
    progressDialog.setCancelable(false);
    progressDialog.show();
    webView.setWebViewClient(new WebViewClient() {
        public void onPageFinished(WebView view, String url) {
            try {
                progressDialog.dismiss();
            } catch (Exception e) {
                e.printStackTrace();

            }
        }

    });
}
1
    myThanh.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);

    final AlertDialog alertDialog = new AlertDialog.Builder(this).create();

    progressBar = ProgressDialog.show(MainActivity.this,"Đang tải dữ liệu",  "Vui lòng chờ...");

    myThanh.setWebViewClient(new WebViewClient() {


        public void onPageFinished(WebView view, String url) {
            if (progressBar.isShowing()) {
                progressBar.dismiss();
            }
        }
    });
jarlh
  • 42,561
  • 8
  • 45
  • 63
1

This simple solution worked for me in KOTLIN:

private fun setupWebView() {

    val webViewClient: WebViewClient = object: WebViewClient() {

        override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
            view?.loadUrl(request?.url.toString())
            return super.shouldOverrideUrlLoading(view, request)
        }

        override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
            showProgressDialog()
            super.onPageStarted(view, url, favicon)
        }

        override fun onPageFinished(view: WebView?, url: String?) {
            hideProgressDialog()
            super.onPageFinished(view, url)
        }
    }
    webView.webViewClient = webViewClient

    webView.settings.javaScriptEnabled = true
    webView.settings.defaultTextEncodingName = "utf-8"
}
Marcelo Gracietti
  • 3,121
  • 1
  • 16
  • 24
  • Sometimes, it looks like onPageFinished is not called for every onPageStarted call, so having a showLoading indicator counter increasing which decreases when a hide call happens leaves a loading indicator on the screen. Happened to me on Galaxy S4 (Android 5.0.1 - WebView Client version 51.0.2704.81), and on a Nougat powered device. – DoruAdryan Jan 30 '18 at 08:51
1

I try dismis progress on method onPageFinished(), but not good too much, it has time delay to render webview.

try with onPageCommitVisible() better:

val progressBar = ProgressDialog(context)
    progressBar.setCancelable(false)
    progressBar.show()

    web_container.webViewClient = object : WebViewClient() {
        override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
            view.loadUrl(url)
            progressBar.show()
            return true
        }

        override fun onPageCommitVisible(view: WebView?, url: String?) {
            super.onPageCommitVisible(view, url)
            progressBar.dismiss()
        }
    }
1

Paste This in your code and add your URL

   var progressDialog: ProgressDialog? = null

private fun startWebView(url: String) {

    val settings = webView.getSettings()

    settings.setJavaScriptEnabled(true)
    webView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY)

    webView.getSettings().setBuiltInZoomControls(true)
    webView.getSettings().setUseWideViewPort(true)
    webView.getSettings().setLoadWithOverviewMode(true)

    progressDialog = ProgressDialog(this)
    progressDialog!!.setMessage("Loading...")
    progressDialog!!.show()

    webView.setWebViewClient(object : WebViewClient() {
        override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
            view.loadUrl(url)
            return true
        }

        override fun onPageFinished(view: WebView, url: String) {
            if (progressDialog!!.isShowing()) {
                progressDialog!!.dismiss()
            }
        }

        override fun onReceivedError(view: WebView, errorCode: Int, description: String, failingUrl: String) {
            Toast.makeText(this@MainActivity, "Error:$description", Toast.LENGTH_SHORT).show()

        }
    })
    webView.loadUrl(url)
}
MazRoid
  • 145
  • 1
  • 12
1

You can use something like that:

override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
    super.onPageStarted(view, url, favicon)
    binding.pbLoader.visibility = ProgressBar.VISIBLE
}

override fun onPageCommitVisible(view: WebView?, url: String?) {
    super.onPageCommitVisible(view, url)
    binding.pbLoader.visibility = ProgressBar.GONE
}
Moro
  • 36
  • 4
0
    WebView webView;
ProgressDialog progressDialog;

TextView text;
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_web_view);


    String message = getIntent().getStringExtra("key").toString();
    setTitle(message);
    Bundle isNetworkAvailable = getIntent().getExtras();

    String value = "file:///android_asset/n/o/i/no_connection.html";
    if (isNetworkAvailable()) {
        value = isNetworkAvailable.getString("keyHTML");
    }
    webView = (WebView) findViewById(R.id.kamal);
    webView.loadUrl(value);
    init();
}

private boolean isNetworkAvailable() {
    ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
    return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}

private void init() {
    webView = (WebView) findViewById(R.id.kamal);
    webView.getSettings().setBuiltInZoomControls(true);
    webView.setBackgroundColor(0);
    webView.getSettings().setJavaScriptEnabled(true);
    progressDialog = new ProgressDialog(WebView_Online.this);
    progressDialog.setMessage("Loading Please wait...");
    progressDialog.setCancelable(false);
    progressDialog.show();
    webView.setWebViewClient(new WebViewClient() {
        public void onPageFinished(WebView view, String url) {
            try {
                progressDialog.dismiss();
            } catch (Exception e) {
                e.printStackTrace();

            }
        }

    });
}
0

A better way to showing loader when page is loading in Webview I created a loader in BaseActivity :-

lateinit var loader: Dialog


loader = Loader.getLoader(this)

in Webview Activity

webView.settings.javaScriptEnabled = true
        webView.addJavascriptInterface(MyJavaScriptInterface(this@MbWayWebViewActivity), "HtmlViewer")
        webView.settings.setSupportZoom(true)
        webView.settings.builtInZoomControls = true

        webView.webViewClient = object : WebViewClient() {
            @Deprecated("Deprecated in Java")
            override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
                loader.show()
                return false
            }
            override fun onPageFinished(view: WebView?, url: String?) {
                super.onPageFinished(view, url)
                loader.dismiss()
                binding.webView.loadUrl("javascript:HtmlViewer.showHTML" + "('<html>'+document.getElementsByTagName('html')[0].innerHTML+'</html>');")

            }
        }

show loader in shouldOverrideUrlLoading method and dismiss loader inside onPageFinished.

Hope your problem resolve ..