25

I'm working with PhoneGap and Android and have my .html and js files on an external server. When I use the following code, the app loads my external .html files and everything works fine:

this.setIntegerProperty("loadUrlTimeoutValue", 60000);
this.loadUrl("http://www.myserver.com");

However, when work via a WebView I can't seem to set the loadURLTimeoutValue for a WebView:

private WebView webView;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);  

try {
     webView = (WebView) findViewById(R.id.webview);    
     webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
     webView.loadUrl("http://www.myserver.com");     
}

This doesn't work. How can I set the timeout value on the WebView?

Paul Chu
  • 1,249
  • 3
  • 19
  • 27
user989557
  • 929
  • 2
  • 11
  • 18

6 Answers6

27

This is a workaround to simulate the described behavior. You can use a WebViewClient, and override the onPageStarted method:

public class MyWebViewClient extends WebViewClient {
    boolean timeout;

    public MyWebViewClient() {
        timeout = true;
    }

    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                timeout = true;

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if(timeout) {
                    // do what you want
                }
            }
        }).start();
    }

    @Override
    public void onPageFinished(WebView view, String url) {
        timeout = false;
    }
}

If timeout, you can load, for example, an error page...

To add the WebViewClient to you WebView, just do this:

webView.setWebViewClient(new MyWebViewClient());
Mehul Kabaria
  • 6,404
  • 4
  • 25
  • 50
Vito Gentile
  • 13,336
  • 9
  • 61
  • 96
  • If there is a timeout, you could try to add some controls inside the `if` statement to verify if the page is half loaded – Vito Gentile Oct 18 '13 at 10:00
  • 3
    There is a problem if a page loads successfully and if you load another page when the thread has not finished running... Also, your constructor is incorrect and you should set the timeout to true in the `onPageStarted` method! – andreas Jul 17 '14 at 10:49
  • 2
    how do u cancel the loading of the web site once it smed out? – Jono Sep 18 '15 at 11:12
  • how to handle if onPageFinished called multiple times – Amit Verma Dec 05 '18 at 12:58
  • This wont work for multiple concurrent calls. One call will interfere other. – Sazzad Hissain Khan Nov 06 '19 at 07:26
  • this method doesnt work, in case of connection timeout pageStarted is fired at the end of the network timeout – Tobia Mar 27 '23 at 11:17
16

I used this to set a time out for my WebView:

public class MyWebViewClient extends WebViewClient {

    boolean timeout = true;

    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        Runnable run = new Runnable() {
            public void run() {
                if(timeout) {
                    // do what you want
                    showAlert("Connection Timed out", "Whoops! Something went wrong. Please try again later.");
                }
            }
        };
        Handler myHandler = new Handler(Looper.myLooper());
        myHandler.postDelayed(run, 5000);
    }

    @Override
    public void onPageFinished(WebView view, String url) {
        timeout = false;
    }
}
Nick
  • 9,285
  • 33
  • 104
  • 147
  • what does "myHandler" refer to here? i tried the solution before yours, but the code i wanted to run caused an exception saying i need to run my code in the UI thread. Your solution uses the "postDelayed" method, which in theory should run the code in the UI thread, is that right? im just confused as to what the "myHandler" in front of the "postDelayed" is? could you flesh the example out with the myHandler code, or a simple example of how you would define the myhandler code. – user280109 Jul 18 '13 at 16:24
  • myHandler is presumably initialized as new Handler() in the main (UI) thread. Look at the Android documentation on Handler and Looper for more info. It's not clear from the documentation whether onPageFinished() will be called under all circumstances - e.g. if an error occurs or a WebView.stopLoading() call is made. – MZB Apr 17 '14 at 04:29
  • myHandler = new Handler(Looper.myLooper()); – Rodrigo Jul 31 '15 at 18:39
8

The correct way to change the default timeout is using tag <preference /> in config.xml file, for example:

<preference name="loglevel" value="DEBUG" />
<preference name="loadUrlTimeoutValue" value="60000" />
<preference name="errorUrl" value="file:///android_asset/www/connection_error.html" />

For more preference options, refer to Android Configuration.

shimatai
  • 1,759
  • 16
  • 18
1

If you extend CordovaWebView, which you should in order to get the phonegap API, you can just use the following:

this.getIntent().putExtra("loadUrlTimeoutValue", 60000);

Internally, CordovaWebView implements a timeout mechanism similar to the ones proposed in the previous post (default timeout = 2000).

Mind that this is not a documented interface, so it might break in the future.

bertvh
  • 821
  • 1
  • 7
  • 17
1
WebView mWebView = findViewById(R.id.web_view);
mWebView.setWebViewClient(new WebViewClient() {
    private volatile boolean timeout;
    private volatile String timeoutOnPageStartedURL;
    private volatile String timeoutCurrentURL;

    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        super.onPageStarted(view, url, favicon);

        timeout = true;
        timeoutOnPageStartedURL = url;
        timeoutCurrentURL = view.getUrl();

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (timeout) {
                    view.post(new Runnable() {
                        @Override
                        public void run() {
                            String currentURL = view.getUrl();
                            if ((timeoutOnPageStartedURL.hashCode() == currentURL.hashCode()) ||
                                (timeoutCurrentURL.hashCode() == currentURL.hashCode())) {
                                // do what you want with UI   
                            }                                     
                        }
                    });
                }
            }
        }).start();
    }

    @Override
    public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);

        timeout = false;
    }
});
Alexander Savin
  • 1,952
  • 1
  • 15
  • 30
0

The use of Thread class bothers me calling the WebView from the run function will lead to an exception as the WebView is created and used in another thread. I would perform this with an AsyncTask. In this example, I use an AsyncTask to load an error file into the WebView if the timeout was reached. If the page loads properly I cancel the AsyncTask. The onPostExecute runs in the UI thread so there is no thread safety problem to interact with the WebView:

private class CustomWebViewClient extends WebViewClient {
    boolean mPageLoaded;
    final int mTimeoutLength = 20000;
    WebView mView;
    TimeoutCheck timeoutCheckTask;

    public CustomWebViewClient()
    {
        super();
        mPageLoaded = false;
    }

    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        mView = view;

        timeoutCheckTask  = new TimeoutCheck();
        timeoutCheckTask.execute(null,null);
    }

    public void onPageFinished(WebView view, String url) {
        mPageLoaded = true;
        timeoutCheckTask.cancel(true);
    }

    private class TimeoutCheck extends AsyncTask<Void, Void, Void> {
        protected Void doInBackground(Void... params) {
            long count = 0;
            while (count < mTimeoutLength)
            {
                try
                {
                    Thread.sleep( 1000 );
                }
                catch ( InterruptedException e )
                {
                    e.printStackTrace();
                }

                // Escape early if cancel() is called
                if (isCancelled()) break;
                count += 1000;
            }
            return null;
        }

        protected void onPostExecute(Void result) {
            if(!mPageLoaded) {
                mbLoadedErrFile = true;
                //load error file into the webview
                mView.loadUrl("file:///android_asset/url_err_timeout.html");
            }
        }
    }
Itamar Kerbel
  • 2,508
  • 1
  • 22
  • 29