clearInterval() workaround for some Android browsers

Speedy is written with Cordova, using HTML and Javascript to create an installable (and sellable) Andorid app. Cordova uses the Android browser to render the appliation, which in general works quite well. However, I ran into a problem on some devices with window.clearTimeout(), and it took me a while to work around it.

At its core, Speedy is just a function that runs every so often to display some text. The idiomatic way to do this in Javascript is with setInterval(). In the simplest case, you'd use it like this:

var intervalId = window.setInterval(function(){console.log("Hi")}, 1000);

When you want to cancel the interval, you'd use cancelInterval():

window.cancelInterval(intervalId);

This all works fine, even on the 'problem' browsers. In fact, moving back to this simpler usage ended up being the solution to my problem.

Because I'm using Angular, I decided to make a somewhat more idiomatic wrapper for setInterval():

function $interval(fn, ms){
    var t = window.setInterval(function(){$scope.$apply(fn)}, ms);
    return function(){ window.clearInterval(t)};
}

...

var stop = $interval(function(){console.log('Hi')}, 1000);

...

stop();

To me this nicely encapsulates the set/clearInterval() calls. It works in desktop browsers, on my Nexus 4, and even on my ancient Huawei 8150 running Android 2.3. It failed on my Samsung Galaxy S running 4.2.2, and I had reports of it failing on an HTC One S running 4.1.1 and on an HP tablet.

I haven't precisely tracked down the issue, but it seems that the function returned by $interval is failing to properly close over t. In any case, the solution was to return the interval id, rathern than a function, and pass it to window.cancelInterval() when required.

On a related note, as part of my testing I found that Angular's $timeout() (which wraps window.setTimeout()) also does not work on some Android browsers. Even worse than with setInterval(), $timeout() never starts at all. I'm not sure if this is an issue with closures in general (although I use them elsewhere in the codebase), or if somehow interval/timeout are particularly sensitive to being wrapped.

comments powered by Disqus