setTimeout/setInterval Bug in Android 2.2 WebKit

If you develop web apps for Android devices, there's a really gnarly bug you should be aware of: setTimeout and setInterval will never fire while the soft keyboard is open.  When the soft keyboard closes, all the queued up timeouts/intervals will unspool all at once, which is not terribly good, but better than them disappearing.  Note that it's the timer checks which are put into stasis, so you'll get at most one fire per setInterval, regardless of how long the keyboard was open (e.g., a 500ms interval will fire once, even if they keyboard is open for many seconds).

The most damning place this bug rears it's head is with autocompletion scripts on form fields.  You necessarily focus the field, bringing up the keyboard, in order to interact with it.  But as soon as you do all your JS can't do timer-based actions.  If you have a naive implementation that responds directly to key events, you'll be ok, but particularly if you're doing remote data retrieval for the autocomplete dropdown, you're going to delay responding to key events so you can collapse multiple events which are temporally close into a single remote call.  Which means you're never going to get to making that call until the user removes focus from the form field.  Oof.

In many cases, you can code around the bug with a little trickery.  For example, on a key event, you can record the current time, and then set your timeout.  On the next key event, if your timeout hasn't triggered, but it's been longer than the delay, you can switch the autocomplete mechanism into direct invocation mode.  Hardly ideal, as it requires manual coding for every timeout/interval structure you have in your code, but it does work, and doesn't make everyone pay the price for the Android bug.  For simple autocomplete, this works reasonably well, but it doesn't do so hot for more complex situations.

Hopefully Google will get the bug (Issue 13540) fixed in the near future, and carriers will allow the update to trickle out to their devices.  But even in the best case scenario, that's still months away.

2 responses to “setTimeout/setInterval Bug in Android 2.2 WebKit”

  1. Dan G. Switzer, II

    @Barney:

    This seems like a perfect use case for debouncing a function (which is essentially the way you mention solving it.) If you haven't seen it, there's a great function to easily implementing deboucing:

    http://blog.pengoworks.com/index.cfm/2009/3/24/Managing-JavaScript-eventsfunctions-using-debouncing

    The concept I blog about is actually based on work by John Hann, but my blog has some examples his original article is lacking.

    What's great, is you can easily add to any existing code w/very little effort:

    Old (i'm using jQuery syntax for simplicity/readability):

    $("#id).click(function (){
    // do something
    });

    New, with debouce() prototype:

    $("#id).click(function (){
    // do something
    }.debounce(100));

    Using the debounce technique above, any time a call is made to the function w/in 100ms, then the code is canceled.

    Unfortunately, the debounce() itself is based upon the setTimeout() function, so it's going to add more to the queue–but the execution of the debouce calls is pretty lightweight and will at least reduce the heavy work such as an AJAX call.