我有一个WebView
从Internet上加载页面.我想显示一个ProgressBar
直到加载完成.
我如何监听完成页面加载WebView
?
扩展WebViewClient并调用onPageFinished(),如下所示:
mWebView.setWebViewClient(new WebViewClient() { public void onPageFinished(WebView view, String url) { // do your stuff here } });
@ian这不是100%准确.如果页面中有多个iframe,则会有多个onPageFinished(和onPageStarted).如果你有几个重定向,它也可能会失败.这种方法解决了(几乎)所有问题:
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; //HIDE LOADING IT HAS FINISHED } else { redirect = false; } } });
更新:
根据文档:当嵌入框架的内容发生变化时,不会调用onPageStarted,即单击目标为iframe的链接.
我在Twitter上发现了一个特定的案例,其中只有一个pageFinished被调用并且稍微搞乱了逻辑.为了解决这个问题,我添加了一个计划任务,在X秒后删除加载.在所有其他情况下都不需要这样做.
更新2:
现在使用当前的Android WebView实现:
boolean loadingFinished = true; boolean redirect = false; mWebView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading( WebView view, WebResourceRequest request) { if (!loadingFinished) { redirect = true; } loadingFinished = false; webView.loadUrl(request.getUrl().toString()); return true; } @Override public void onPageStarted( WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); loadingFinished = false; //SHOW LOADING IF IT ISNT ALREADY VISIBLE } @Override public void onPageFinished(WebView view, String url) { if (!redirect) { loadingFinished = true; //HIDE LOADING IT HAS FINISHED } else { redirect = false; } } });
我非常偏爱@NeTeInStEiN(和@polen)解决方案但是会用计数器实现它而不是多个布尔或状态监视器(只是另一种味道,但我认为可能会分享).它确实有一个关于它的JS细微差别,但我觉得逻辑更容易理解.
private void setupWebViewClient() { webView.setWebViewClient(new WebViewClient() { private int running = 0; // Could be public if you want a timer to check. @Override public boolean shouldOverrideUrlLoading(WebView webView, String urlNewString) { running++; webView.loadUrl(urlNewString); return true; } @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { running = Math.max(running, 1); // First request move it to 1. } @Override public void onPageFinished(WebView view, String url) { if(--running == 0) { // just "running--;" if you add a timer. // TODO: finished... if you want to fire a method. } } }); }
我简化了NeTeInStEiN的代码是这样的:
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; } } });
很容易理解,OnPageFinished如果前一个回调是在onPageStarted上,那么页面是完全加载的.
如果您想要显示进度条,则需要监听进度更改事件,而不仅仅是完成页面:
mWebView.setWebChromeClient(new WebChromeClient(){ @Override public void onProgressChanged(WebView view, int newProgress) { //change your progress bar } });
顺便说一下,如果你想只显示一个Indeterminate ProgressBar,那么覆盖onPageFinished方法就足够了
我找到了一个优雅的解决方案,但没有经过严格的测试:
public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); if (m_webView.getProgress() == 100) { progressBar.setVisibility(View.GONE); m_webView.setVisibility(View.VISIBLE); } }
使用setWebViewClient()并覆盖onPageFinished()
您可以通过webview类中的getProgress方法跟踪Progress Staus .
初始化进度状态
private int mProgressStatus = 0;
然后像这样加载AsyncTask:
private class Task_News_ArticleView extends AsyncTask{ 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(); } } }
谢谢你的回答.它帮助了我,但我必须根据我的需要改进它.我有几个页面和完成,所以我添加了一个计时器,检查是否启动了pagefinish新的pagestart.好的,不好的解释.看代码:)
myWebView.setWebViewClient(new WebViewClient() { boolean loadingFinished = true; boolean redirect = false; long last_page_start; long now; // Load the url public boolean shouldOverrideUrlLoading(WebView view, String url) { if (!loadingFinished) { redirect = true; } loadingFinished = false; view.loadUrl(url); return false; } @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { Log.i("p","pagestart"); loadingFinished = false; last_page_start = System.nanoTime(); show_splash(); } // When finish loading page public void onPageFinished(WebView view, String url) { Log.i("p","pagefinish"); if(!redirect){ loadingFinished = true; } //call remove_splash in 500 miSec if(loadingFinished && !redirect){ now = System.nanoTime(); new android.os.Handler().postDelayed( new Runnable() { public void run() { remove_splash(); } }, 500); } else{ redirect = false; } } private void show_splash() { if(myWebView.getVisibility() == View.VISIBLE) { myWebView.setVisibility(View.GONE); myWebView_splash.setVisibility(View.VISIBLE); } } //if a new "page start" was fired dont remove splash screen private void remove_splash() { if (last_page_start < now) { myWebView.setVisibility(View.VISIBLE); myWebView_splash.setVisibility(View.GONE); } } });