setInterval functions not running when app in background - javascript

I'm developing a simple app with phonegap which every 30 seconds send user current coordinates to my database via ajax call.It works very well
$(document).ready(function() {
setInterval(function() {
SetLocationUpdates();
}, 30000);
});
If the app is in the foreground there is no problem and everything works fine, but if I open google maps app with this code
<div><a href="geo:41.897096,27.036545">Open maps app</div>
My app goes in the background(my app and google map app work separately.Two apps work at same time) and the interval function is not executed any more.
Is it possible to have the javascript code (a timer function) executing in the background with phonegap?
Edited:
I use cordova-plugin-background-mode(https://github.com/katzer/cordova-plugin-background-mode) but it still does not work.And alert give false.What is wrong with this?
document.addEventListener('deviceready', function () {
cordova.plugins.backgroundMode.enable();
alert(cordova.plugins.backgroundMode.isActive());
}, false);

I was looking for a solution to the same problem, and I think I just found one, though I haven't been able to fully try this out yet, I thought I'd post the answer here anyways, so you can try it out too.
One solution would be to set the timer in native code, instead of JavaScript, and there seems to be a Cordova plugin for just such a purpose:
https://github.com/dukhanov/cordova-background-timer
After installing the Cordova plugin, you can use it like this (pasted from the documentation):
var eventCallback = function() {
// timer event fired
}
var successCallback = function() {
// timer plugin configured successfully
}
var errorCallback = function(e) {
// an error occurred
}
var settings = {
timerInterval: 60000, // interval between ticks of the timer in milliseconds (Default: 60000)
startOnBoot: true, // enable this to start timer after the device was restarted (Default: false)
stopOnTerminate: true, // set to true to force stop timer in case the app is terminated (User closed the app and etc.) (Default: true)
hours: 12, // delay timer to start at certain time (Default: -1)
minutes: 0, // delay timer to start at certain time (Default: -1)
}
window.BackgroundTimer.onTimerEvent(eventCallback); // subscribe on timer event
// timer will start at 12:00
window.BackgroundTimer.start(successCallback, errorCallback, settings);

if you are still looking for an answer for this issue , or it can help someone else:
im sure that you are facing this problem in android so to resolve this you should add this piece of code after you add background-mode cordova plugin to your project :
this.backgroundMode.enable();
this.backgroundMode.on('activate').subscribe(()=>{
this.backgroundMode.disableWebViewOptimizations();
});

Related

Angular 2 application on mobile browser (sleep detection)

After mobile phone puts the browser to sleep, and stays like that for a longer period of time, after wake up it displays wrong data, which otherwise perfectly updates all the data on the page. Is there a way to detect wake up event and what's the best Angular way to reload page/component in that case?
A simple way to achieve this could be run a timer to detect if the browser is asleep.
Using RxJS timeinterval operator,
http://reactivex.io/documentation/operators/timeinterval.html
Rx.Observable.timer(0, 1000).timeInterval().subscribe(timer => {
if (timer.interval > (1000 + SLEEP_THRESHOLD)) {
console.log ('wake-up from sleep detected');
}
});
Other simple way could be,
var now = new Date().getTime();
setInterval (function () {
if ((new Date().getTime() - now) > SLEEP_THRESHOLD) {
console.log ('wake-up from sleep detected');
}
now = new Date().getTime();
}, 1000);
You can reload your app by simply calling JS function
location.reload()
or if you want a more Angular style approach you can try calling your
route again
this.router.navigate(["myRoute"]);
Regarding sleep on mobile browsers you can check out NoSleep.js maybe it can serve your purpose.

Geolocation watch doesn't fire consistently

I've got a test app that fetches lat/lng values from the HTML5 geolocation service. Unfortunately, it's firing at rather inconsistent time intervals, anywhere from 500ms to 10000ms. I've tried changing the maximimAge and timeout parameters for the watch but those don't seem to change anything. I'm testing it in Chrome as well as via a simple Cordova app on an Android Lollipop build. The code below simply displays the timestamp value of the watch to eliminate any other delays that could be causing the issue. It appears that the interval is close to a 1 second then 5 second repeating pattern. I've also tried placing the geolocation fetch function inside a setInterval function and it behaves with the same 1 and 5 second repeating interval.
<html>
<body>
<h1>Timestamp</h1>
<div id="mytimestamp"></div>
<button id="btnstopwatch">Stop GPS</button>
</body>
</html>
<script type="text/javascript">
var mytimestamp = document.getElementById("mytimestamp");
//start watching location
watchPositionId = navigator.geolocation.watchPosition(updateCompass,handleerror,{
enableHighAccuracy:true,
maximumAge:3000,
timeout:3000
});
function updateCompass(p)
{
mytimestamp.innerHTML = p.timestamp;
}
function handleerror(err)
{
if(err.code ==1)
{
//user said no
alert('Please allow access to GPS');
}
else
{
alert(err.code);
}
}
</script>
Relating to watchPosition(), on the following link w3 says "the successCallback is only invoked when a new position is obtained .......implementations may impose limitations on the frequency of callbacks so as to avoid inadvertently consuming a disproportionate amount of resources."
What it means is that watchPosition() is waiting for events which will cause changes in position to happen, otherwise it does nothing. So watchPosition() will not be calling updateCompass() unless it sees the changes in position.
Also, in regard watchPosition(), maximumAge and timeout parameters are related to the acquiring new position, and these parameters has nothing to do with how much times and when watchPosition() is called...
WatchPosition() prevents continuous calls to see if position changes or not, and reacts only if some events related to position changes occur, this help to save resources like battery. But if you really want to see the position, let's say every three second, no matter if position changed or not I think setting an interval will be good approach.
var watchPositionId;
//start watching location
setInterval(function () {
watchPositionId = navigator.geolocation.watchPosition(updateCompass, handleerror, {
enableHighAccuracy: true,
maximumAge: 3000,
timeout: 3000
});
}, 3000);
function updateCompass(p) {
mytimestamp.innerHTML = p.timestamp;
// if you have alert message it will counts seconds once you dismiss the alert,
//this may be part of the issue why you kept getting diffrent intervals.
//alert(p.timestamp);
navigator.geolocation.clearWatch(watchPositionId);
}
You mentioned that you tried to setInterval and it didn't work, so please note that I commented alert() in the code above because it caused me to have delays, without it the time stamp in html updates every 3000ms with an accuracy about 5ms.
The above approach works if you want to use watchPosition() because clearWatch() stoppes the watchPosition() and it further callbacks. Basically the code above initiates new watchPosition() every three seconds and kills it with clearWatch(). That is being said I think watchPosition() is not the best method to use in this approach unless you expect significant changes in position within this time interval. I would rather use getCurrentPosition() since it does the job and doesn't wait for changes in position.
var watchPositionId;
//start watching location
setInterval(function () {
watchPositionId = navigator.geolocation.getCurrentPosition(updateCompass, handleerror, {
enableHighAccuracy: true,
maximumAge: 3000,
timeout: 3000
});
}, 3000);
function updateCompass(p) {
mytimestamp.innerHTML = p.timestamp;
}
I ended up changing the solution to use both geolocation as well as the deviceOrientationEvent. Using the geolocation event alone created a very 'jerky' response and the device orientation event smooths this out.
Here's the setInterval function set to fetch the geolocation every ten seconds:
window.onload = function()
{
//fetch new GPS info every 10000 milliseconds
window.setInterval(function ()
{
navigator.geolocation.getCurrentPosition(onGeoSuccess, onGeoFailure, {
enableHighAccuracy: true,
maximumAge: 0,
timeout: 30000 //large timeout to accomodate slow GPS lock on some devices
});
}, 10000); //update current location every ten seconds
};
On geo success:
function onGeoSuccess(location)
{
//call function to calculate bearing
var cluebearing = geo.bearing(currentlat, currentlng, cluelat, cluelng);
//call function to rotate arrow
rotateArrow(cluebearing);
}//end onGeoSuccess()
Function to fetch device orientation and process:
function rotateArrow(mybearing)
{
//Check for support for DeviceOrientation event
if(window.DeviceOrientationEvent)
{
//orientation listener
window.addEventListener('deviceorientation', function(event)
{
var myalpha = event.alpha; //rotation from north
//process orientation change
}//end deviceorientation listener
}
}//end rotateArrow()
On geo failure:
function onGeoFailure()
{
alert('Please turn on your phone\'s GPS');
}

How setInterval and setTimeout behave on Phonegap/Cordova when app resumes from background? [duplicate]

I have a jQuery Mobile web app which targets iOS and Android devices. A component of the application is a background task, which periodically checks for a.) changes to local data and b.) connectivity to the server. If both are true, the task pushes the changes.
I'm using a simple setTimeout()-based function to execute this task. Each failure or success condition calls setTimeout() on the background task, ensuring that it runs on 30 second intervals. I update a status div with the timestamp of the last task runtime for debugging purposes.
In any desktop browser, this works just fine; however, on iOS or Android, after some period of time, the task stops executing. I'm wondering if this is related to the power conservation settings of the devices--when iOS enters stand-by, does it terminate JavaScript execution? That is what appears to happen.
If so, what is the best way to resume? Is there an on-wake event which I can hook into? If not, what other options are there which don't involve hooking into events dependent on user interaction (I don't want to bind the entire page to a click event just to restart the background task).
Looks like Javascript execution is paused on MobileSafari when the browser page isn't focused. It also seems if setInterval() events are late, they are simply fired as soon as the browser is focused. This means we should be able to keep a setInterval() running, and assume the browser lost/regained focus if the setInterval function took much longer than usual.
This code alerts after switching back from a browser tab, after switching back from another app, and after resuming from sleep. If you set your threshold a bit longer than your setTimeout(), you can assume your timeout wouldn't finish if this fires.
If you wanted to stay on the safe side: you could save your timeout ID (returned by setTimeout) and set this to a shorter threshold than your timeout, then run clearTimeout() and setTimeout() again if this fires.
<script type="text/javascript">
var lastCheck = 0;
function sleepCheck() {
var now = new Date().getTime();
var diff = now - lastCheck;
if (diff > 3000) {
alert('took ' + diff + 'ms');
}
lastCheck = now;
}
window.onload = function() {
lastCheck = new Date().getTime();
setInterval(sleepCheck, 1000);
}
</script>
Edit: It appears this can sometimes trigger more than once in a row on resume, so you'd need to handle that somehow. (After letting my android browser sleep all night, it woke up to two alert()s. I bet Javascript got resumed at some arbitrary time before fully sleeping.)
I tested on Android 2.2 and the latest iOS - they both alert as soon as you resume from sleep.
When the user switches to another app or the screen sleeps, timers seem to pause until the user switches back to the app (or when the screen awakens).
Phonegap has a resume event you can listen to instead of polling for state (as well as a pause event if you want to do things before it is out of focus). You start listening to it after deviceReady fires.
document.addEventListener("deviceready", function () {
// do something when the app awakens
document.addEventListener('resume', function () {
// re-create a timer.
// ...
}, false);
}, false);
I use angular with phonegap and I have a service implemented that manages a certain timeout for me but basically you could create an object that sets the timer, cancels the timer and most importantly, updates the timer (update is what is called during the 'resume' event).
In angular I have a scopes and root scope that I can attach data to, my timeout is global so I attach it to root scope but for the purpose of this example, I'll simply attach it to the document object. I don't condone that because you need should apply it to some sort of scope or namespace.
var timeoutManager = function () {
return {
setTimer: function (expiresMsecs) {
document.timerData = {
timerId: setTimeout(function () {
timeoutCallback();
},
expiresMsecs),
totalDurationMsecs: expiresMsecs,
expirationDate: new Date(Date.now() += expiresMsecs)
};
},
updateTimer: function () {
if (document.timerData) {
//
// Calculate the msecs remaining so it can be used to set a new timer.
//
var timerMsecs = document.timerData.expirationDate - new Date();
//
// Kill the previous timer because a new one needs to be set or the callback
// needs to be fired.
//
this.cancelTimer();
if (timerMsecs > 0) {
this.setTimer(timerMsecs);
} else {
timeoutCallback();
}
}
},
cancelTimer: function () {
if (document.timerData && document.timerData.timerId) {
clearTimeout(document.timerData.timerId);
document.timerData = null;
}
}
};
};
You could have the manager function take a millisecond parameter instead of passing it into set, but again this is modeled somewhat after the angular service I wrote. The operations should be clear and concise enough to do something with them and add them to your own app.
var timeoutCallback = function () { console.log('timer fired!'); };
var manager = timeoutManager();
manager.setTimer(20000);
You will want to update the timer once you get the resume event in your event listener, like so:
// do something when the app awakens
document.addEventListener('resume', function () {
var manager = timeoutManager();
manager.updateTimer();
}, false);
The timeout manager also has cancelTimer() which can be used to kill the timer at any time.
You can use this class github.com/mustafah/background-timer based on #jlafay answer , where you can use as follow:
coffeescript
timer = new BackgroundTimer 10 * 1000, ->
# This callback will be called after 10 seconds
console.log 'finished'
timer.enableTicking 1000, (remaining) ->
# This callback will get called every second (1000 millisecond) till the timer ends
console.log remaining
timer.start()
javascript
timer = new BackgroundTimer(10 * 1000, function() {
// This callback will be called after 10 seconds
console.log("finished");
});
timer.enableTicking(1000, function(remaining) {
// This callback will get called every second (1000 millisecond) till the timer ends
console.log(remaining);
});
timer.start();
Hope it helps, Thank you ...
You should use the Page Visibility API (MDN) which is supported just about everywhere. It can detect if a page or tab has become visible again and you can then resume your timeouts or carry out some actions.

What is the best way to check internet connection

I made a CMS which during operation pulls large amounts of data.
CMS is made in PHP, MySQL, jQuery, Bootstrap and use AJAX.
The problem is if you lose your internet connection can cause problems on displaying and scrolling.
I would love if there is a good way to show the error and blocks all functions on the site when there is no internet connection. When the connection is established it should be all function allowed on the site.
Thanks!
(Sorry for my bad English.)
If you are using jQuery, you can just hook on the global error handler and lock up your application when an error occurs. The lock up screen could simply ask to try again.
$( document ).ajaxError(function() {
// lock your UI here
});
Also, once the UI is locked, you could execute a function that would ping your server in an Exponential Backoff fashion and automatically unlock the application on network restore.
Locking your app can easily be done with jQuery's blockUI plugin.
Example
(function ($) {
var locked = false;
var errorRetryCount = 0;
var blockUiOptions = { message: "Oops! Could not reach the server!" };
// change this function to adjust the exponential backoff delay
function backoff(n) {
return Math.pow(2, n) * 100;
}
$(function () {
$( document ).ajaxError(function () {
var req = this;
errorRetryCount += 1;
if (!locked) {
locked = true;
$.blockUI(blockUiOptions);
}
// retry to send the request...
setTimeout(function () { $.ajax(req); }, backoff(errorRetryCount));
}).ajaxSuccess(function () {
locked && $.unblockUI();
locked = false;
errorRetryCount = 0;
});
});
})(jQuery);
Note: You may not want to retry indefinitely your request upon network failure, and would want to quit retrying at some point. Since this is out of the scope of this question, I'll leave it as it is. However, you may take a look at this related question, which may help you sort this part out.
If you're using jQuery already, you could create a simple ajax call to your server, and if it fails within a couple of seconds, either your server or the clients internet connection is down.
Something like this:
setInterval(function() {
$.ajax({
url: "https://cms.example.com/ping",
})
.fail(function( data ) {
alert('Connection lost?');
// remember do to something smart which shows the error just once
// instead of every five seconds. Increasing the interval every
// time it fails seems a good start.
});
}, 5*1000);
Using plain JavaScript and simple code:
window.navigator.onLine ? 'on' : 'off'
It supports by almost every browser, please check Can I use
edit: re-read your question and misunderstood my first pass through so this wouldn't be valid for continuous monitoring... but i'll leave it here anyways as it may be useful for someone else.
i would suggest loading a small js file that adds a class to an element of your page and then checking if that class is applied after the fact... assuming you are using jQuery
file on the remote server loaded into your page after jQuery via script tag
$('html').addClass('connected');
local code
if($('html').hasClass('connected')) {
// connected
} else {
// not connected
}

How can I make my javascript chat polling script be more efficient?

For some reason this check for new chat messages causes a larger amount of browser (and to some extent server) load than I would expect. Anyone see any ways that I can make it more efficient, to lessen the load?
// Begin the cycle of refreshing the mini chat after the standard delay.
function startRefreshingMinichat(){
var secs = 30; // Chat checking frequency.
setTimeout(function (){
checkForNewChats();
startRefreshingMinichat(); // Loop the check for refresh.
}, secs*1000);
}
// Check for the latest chat and update if it's different.
function checkForNewChats(){
// Check whether the latest chat doesn't match the latest displayed chat.
// NOTE THAT THIS CALLBACK DOES NOT TRIGGER IMMEDIATELY.
$.getJSON('api.php?type=latest_chat_id&jsoncallback=?', function(data){
var newChats = false;
// Update global data stores if an update is needed.
if(updateDataStore(data.latest_chat_id, 'chat_id', 'latestChatId', 'chat_id')){
newChats = true;
}
if(newChats){ // there are new chats to show.
refreshMinichat(null, 50); // loads new chat content.
}
// Since this callback isn't immediate, any feedback has to occur whenever the callback finishes.
}); // End of getJSON function call.
}
Check out CometD. It's a js long-polling system I've used with some success for simple chat systems integrated with jQuery. (Last time I looked, there were a few jQuery specific implemetations, but I never found one that was robust enough for me.)
you can checkout this push engine so that you have not to poll for new data anymore.
check it out, its really cool.

Categories