加载WebView时的Android进度条

59
在我的应用中,我有一个WebView,可以加载来自互联网的任何URL。由于网络缓慢,有时页面需要很长时间才能加载,用户只会看到一个空白屏幕。

我想在WebView加载时显示一个ProgressBar,并在WebView完全加载后隐藏ProgessBar

我知道如何使用ProgressBarAsyncTask,但这是我的问题所在。

这是我用来加载WebView的代码。

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

这是我的自定义 WebViewClient

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

现在,如果我想使用 AsyncTask 显示 ProgressBar,那么我想我必须将加载 URL 的代码放入 AsyncTask 中的 doInBackground() 函数中,并通过 onProgressUpdate() 函数显示进度。

但是,我该如何在 doInBackground() 中加载URL呢?因为 doInBackground()非 UI 线程 上运行,我无法在其内部使用 mWebView.loadUrl(web_URL)

有什么建议吗?我是否忽略了一些明显的东西?请指导我。


可能重复:https://dev59.com/km855IYBdhLWcg3wc0Dy - Shrikant Ballal
1
在这个Stack Overflow的问题中得到了完美的解释:http://stackoverflow.com/questions/5207540/android-webview - Goofyahead
可能是Android WebView进度条的重复问题。 - e-sushi
http://web.archive.org/web/20120615002739/http://www.chrisdanielson.com/2010/05/04/android-webview-and-the-indeterminant-progress-solution/ - General Grievance
12个回答

78

查看源代码。帮助您解决问题...

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);
    }
}

我认为它会对你有所帮助。

谢谢。


3
为什么需要调用shouldOverrideUrlLoading方法? - winklerrr
1
shouldOverrideUrlLoading方法现已过时:N开发者预览版具有以下方法签名:public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) - Agna JirKon Rx
谢谢,它像魔法一样奏效了,所以给你一个大拇指! - brijexecon
@winklerrr,为了在WebView中保持页面导航,从而使其保持在应用程序内部,我们需要创建一个WebViewClient的子类,并覆盖它的shouldOverrideUrlLoading(WebView webView, String url)方法。 - amoljdv06
你提到的弃用方法和更新版本的文档都明确指出:不要使用请求的URL调用WebView#loadUrl(String),然后返回true。这样会不必要地取消当前加载并以相同的URL开始新的加载。继续加载给定URL的正确方法是简单地返回false,而不调用WebView#loadUrl(String)。 - MoralCode

19

将您的URL传递给这个方法

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);
        }

11

如果您希望在用户每次加载页面时(而不仅仅是第一次加载)显示进度条,则可以使用以下代码:

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>

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
        }
    }
    
在这种情况下,您甚至可以显示确定性进度条。
  1. Using WebViewClient:

     String url = "https://dev59.com/nGgu5IYBdhLWcg3wj3v5";
     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);
    
同时添加方法:
    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);
        }
    }

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();

            }
        }

    });
}

你能否给一些解释? - executable

1
这个简单的解决方案在Kotlin中对我有用:

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"
}

有时候,看起来并不是每次onPageStarted调用都会触发onPageFinished,因此在屏幕上留下了一个加载指示器。当出现隐藏调用时,增加showLoading指示器计数器并减少它可以解决这个问题。我在Galaxy S4(Android 5.0.1 - WebView客户端版本51.0.2704.81)和Nougat设备上遇到过这个问题。 - DoruAdryan

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();
            }
        }
    });

1

我尝试在onPageFinished()方法中取消进度,但效果不是很好,它会延迟渲染webview。

使用onPageCommitVisible()方法更好:

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
将此代码粘贴到您的代码中,并添加您的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)
}

1
你可以使用类似这样的代码:

您可以使用这样的东西:

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
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接