Question

I've built a simple JavaScript-based timer for a mobile webapp; for the sake of example:

var a = 0;
setInterval(function() {
    console.log('a', a);
    a++;
}, 1000);

This runs just fine in both Mobile Safari and Android Browser. It will log to console every second and increment the value of a accordingly. (Okay, Android Browser doesn't have console.log support, but let's assume it does.)

The issue: if the screen times out (i.e. user stopped interacting with the page), the setInterval function pauses. It resumes when the user turns on their screen again. This won't work for me as I need timer to keep running.

The questions: Is there a way to prevent the setInterval function from pausing when the screen times out? If not, is it possible to prevent the screen from timing out? Any other alternatives?

Thanks in advance!

Was it helpful?

Solution

Basically, no. The phone enters a sleep state to save battery when the screen times out. Since you can't see anything anyway, a large number of processing tasks are stopped. Similar things will occur when you change tabs/windows (the page is unloaded from memory). Right now there is no way to request that the device stays on from a web application. Future support in Android for accessing hardware may provide this functionality, but personally I doubt it.

If you need always running support, you'll need to write native applications for both systems (plus on Android it can always run).

OTHER TIPS

You can use the Page Visibility API to detect when the page is hidden or visible. For example, if the user navigates away from the browser and back again or the screen turns off and on.

I used this answer to help create by solution. You will need to store the time you set your interval. Then when the visibilityChange event listener indicates the document is visible again, you can calculate the amount of time that has passed since you first started the interval and update your data as needed.

In my case I was creating a count down timer in my Angular2 project. My page was running on an iPad and the timer was pausing whenever the screen turned off. So I added the event listener in my ngOnInit(). Then when the screen turned back on I could update my timer to show the correct time left since it was started.

I am using the moment npm package to handle my date time. The timerInfo object is a class variable that gets updated by the interval callback. self.zone.run() is used to propagate the changes to the DOM so that the updated time gets displayed.

Written in typescript:

private timerInfo:{
    days?:number,
    hours?:number,
    minutes:number,
    seconds:number
};
private startTime:Moment = moment();
private timerDuration:number = 20;  // in minutes
private timerHandle:any;

ngOnInit() {
    this.setVisibilityListener();
}

private setVisibilityListener():void {
    var self = this;
    var hidden, visibilityState, visibilityChange;

    if (typeof document.hidden !== "undefined") {
        hidden = "hidden";
        visibilityChange = "visibilitychange";
        visibilityState = "visibilityState";
    }

    var document_hidden = document[hidden];

    document.addEventListener(visibilityChange, function () {
        if (document_hidden != document[hidden]) {
            if (document[hidden]) {
                // Document hidden
                console.log("document hidden");
            } else {
                // Document shown
                console.log("document shown; setCountDownTimer()");
                self.setCountDownTimer();
            }

            document_hidden = document[hidden];
        }
    });
}

private setCountDownTimer():void {
    var self = this;
    if (self.startTime) {
        var startMoment = moment(self.startTime);
        var endMoment = startMoment.add(self.timerDuration, "minutes");
        console.log("endMoment: ", endMoment.toISOString());

        self.clearTimer();

        var eventTime = endMoment.unix();
        var currentTime = moment().unix();
        var diffTime = eventTime - currentTime;
        var duration = moment.duration(diffTime * 1000, 'milliseconds');
        var interval = 1000;

        // if time to countdown
        if (diffTime > 0) {
            self.timerHandle = setInterval(() => {
                self.zone.run(() => {
                    var diff = duration.asMilliseconds() - interval;
                    if (diff < 0) {
                        self.clearTimer();
                        self.timerComplete();
                    } else {
                        duration = moment.duration(duration.asMilliseconds() - interval, 'milliseconds');

                        self.timerInfo = {
                            days: moment.duration(duration).days(),
                            hours: moment.duration(duration).hours(),
                            minutes: moment.duration(duration).minutes(),
                            seconds: moment.duration(duration).seconds()
                        };
                        // console.log("timerInfo: ", JSON.stringify(self.timerInfo));
                    }
                });
            }, 1000);
        } else {
            self.timerComplete();
        }
    }
}

private clearTimer():void {
    if (this.timerHandle) {
        clearInterval(this.timerHandle);
        this.timerHandle = null;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top