¿Cómo escuchar si un WebView termina de cargar una URL?

Resuelto Janusz asked hace 54 años • 18 respuestas

Tengo un WebViewque está cargando una página desde Internet. Quiero mostrar un ProgressBarhasta que se complete la carga.

¿ Cómo puedo escuchar la finalización de la carga de la página de un WebView?

Janusz avatar Jan 01 '70 08:01 Janusz
Aceptado

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 avatar Jun 30 '2010 12:06 ian

@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; 
            }
        }
    });
neteinstein avatar Mar 02 '2011 20:03 neteinstein

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);
            }
        } 
Junaid avatar Oct 13 '2015 08:10 Junaid

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.
            }
        }
    });
}
SciSpear avatar Jul 23 '2013 16:07 SciSpear