¿Cómo escuchar si un WebView termina de cargar una URL?
Tengo un WebView
que está cargando una página desde Internet. Quiero mostrar un ProgressBar
hasta que se complete la carga.
¿ Cómo puedo escuchar la finalización de la carga de la página de un WebView
?
Extienda WebViewClient y llame a onPageFinished () de la siguiente manera:
mWebView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
// do your stuff here
}
});
@ian, esto no es 100% exacto. Si tiene varios iframes en una página, tendrá varios onPageFinished (y onPageStarted). Y si tienes varias redirecciones también puede fallar. Este enfoque resuelve (casi) todos los problemas:
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;
}
}
});
ACTUALIZAR:
Según la documentación: NO se llamará a onPageStarted cuando cambie el contenido de un marco incrustado, es decir, al hacer clic en un enlace cuyo destino es un iframe.
Encontré un caso específico como ese en Twitter donde solo se llamó a una páginaFinished y confundió un poco la lógica. Para resolver eso, agregué una tarea programada para eliminar la carga después de X segundos. Esto no es necesario en todos los demás casos.
ACTUALIZACIÓN 2 :
Ahora con la implementación actual de 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;
}
}
});
También encontré una solución elegante, aunque no la he probado rigurosamente:
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
if (webView.getProgress() == 100) {
progressBar.setVisibility(View.GONE);
webView.setVisibility(View.VISIBLE);
}
}
Soy bastante partidario de la solución @NeTeInStEiN (y @polen), pero la habría implementado con un contador en lugar de múltiples booleanos o observadores de estado (solo otra versión, pero pensé que podría compartir). Tiene un matiz JS, pero creo que la lógica es un poco más fácil de entender.
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.
}
}
});
}