I made a program that creates a Service.
The service connects to a website every 5 minutes, collects one line of data and outputs it to a file.
My problem is that it didn't collect the data every 5 minutes. The data was collected once in around 50-70min. Why? Is there something in android that prevents background services from running properly during nights? What is also strange to me, the 50-70 minute breaks happened only when I was not using my phone.
Times it collected the data:
1:40
1:45
1:50
1:55
2:00
2:05
2:10
2:15
2:20
2:25
2:30 I was awake until this.
3:20
4:15
5:00
6:05
6:55
7:55
8:45
10:20
10:50 Woke up at here.
10:55
Your results are not surprising. Android was designed to swipe out (and back in) processes based overall level of resource as well as other factors.
Modifying your service to become a foreground service will certainly improve your results:
Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);
Foreground services are basically services guaranteed by Android to be less susceptible to swipe out,
which is what you want.
But even a foreground service will halt its processing when the devices goes to sleep. And, if you feel your polling logic is important enough so to keep the device from sleeping, you should also acquire a wakelock.
Note: Long running wakelocks have a huge impact of on battery usage. Handle with care!
Finally, please consider using an alarm for your task. Alarms are usually considered better option for
long running polling tasks.
Depending of an approach you use to schedule your updates, the OS might shift updates to decrease battery drain and overall burden. Delayed tasks might be postponed if the device falls into deep sleep (happens at night mostly as the device is inactive during long periods of time).
It's done this way to prevent your battery to be drained to fast. If you really want to wake your device every 5 minutes, you can check the answer to this post and use the AlarmManager
Related
A core functionality of my app is that it has an ongoing notification with a countdown timer that updates every minute - even if the app gets shut down by Android OS.
First I was using a service to run the timer and update the notification, but this was a memory/battery hog. So I switched to using AlarmManager to finish the timer and a repeating alarm to wake up every 60 seconds or so to update the notification:
Intent repeatingIntent = new Intent(this, AlarmReceiver.class);
repeatingIntent.putExtra(PERFORM_ACTION, ALARM_ACTION_UPDATE_NOTIFICATION);
PendingIntent repeatingAlarmIntent = PendingIntent.getBroadcast(this,
REQUEST_CODE_UPDATE_NOTIFICATION, repeatingIntent, 0);
AlarmManager am = (AlarmManager)this.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime()+1000,
REPEATING_ALARM_INTERVAL*1000, repeatingAlarmIntent);
This works on most devices I've tried it on (and it's much kinder on RAM/battery/CPU) but on Galaxy S6 for example, the repeating alarm is being triggered only every 5 minutes or even less frequently. It sometimes get triggered on time when the device is plugged in but it is very inconsistent. I've tried setting the repeating interval to 30 seconds or less, but it has no effect, the alarm is not triggered (I see every time it's triggered in LogCat). Other, non-repeating alarms are triggered on time.
What would be a good way to ensure that the ongoing notification is updated at least every 60 seconds come hell or high water? Other than going back to using a service (ugh! plus the OS sometimes outright kills the service on devices with little RAM), the only other thing that comes to mind is to set like 5 different repeating alarms (with different request codes) and have each one trigger every 5 minutes in a staggered fashion.
Instead of using setRepeating() use setExact() or setWindow() and set a new alarm each time it's fired. This works well above API19.
even if the app gets shut down by Android OS
No luck. When app gets killed by OS then it is dead and will not be able to do much, incl. posting notification.
being triggered only every 5 minutes or even less frequentl
https://developer.android.com/reference/android/app/AlarmManager.html says:
"Note: Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS
will shift alarms in order to minimize wakeups and battery use."
More on this also here: https://developer.android.com/training/scheduling/alarms.html
Recently, in my timer app, running the timer for the first time causes it to fire an alarm approximately two or three seconds after it should. The strange this is, it only does this the first time I run the timer after installing the app via Android Studio. Every time after that, it runs as expected and the timer goes off after the expected time.
Here is the relevant code:
if(LOG) Log.v(TAG,"Starting the timer service: "+ TimerUtils.time2humanStr(context, mTime));
Intent intent = new Intent( this, TimerReceiver.class);
mPendingIntent = PendingIntent.getBroadcast( this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mAlarmMgr.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + mTime, mPendingIntent);
The variable mTime is set properly each time, according to the logcat output:
Starting the timer service: 5 seconds
And it works fine every time after the initial run. It was working fine before; could it be a problem with Android or Android Studio? Or am I needing to initialize something? I know I can't expect precise answers without dumping all my code here, I'm just looking for hints (speculation?) as to why this behaviour might be occurring.
Are you using API 19? Check out this note in the documentation:
Note: Beginning in API 19, the trigger time passed to this method is
treated as inexact: the alarm will not be delivered before this time,
but may be deferred and delivered some time later. The OS will use
this policy in order to "batch" alarms together across the entire
system, minimizing the number of times the device needs to "wake up"
and minimizing battery use. In general, alarms scheduled in the near
future will not be deferred as long as alarms scheduled far in the
future.
Source: AlarmManager
I need to do a background check in my app, basically polling various URLs for new stuff. So I've read this is done with the AlarmManager.
The thing is, I don't need the user to be notified as soon as new stuff arrives. Let's say I'm checking every hour, I'm perfectly fine with not doing any check while the phone is sleeping, and resuming the checks when the phone is used. That way the user eventually gets the notification, but the drain is minimal.
So I've tried with setInExactRepeating. I'm starting it at boot time, but also at app startup (mostly for the session after install, and to make sure it's running even if the app gets "force killed"). How do I prevent all these checks to add up? (A new check should only be run if none is running, or the previous one needs to be stopped).
I've found setInexact Repeating coupled with ELAPSED_REALTIME (or RTC) works quite well to achieve very minimal battery drain. Using the flag FLAG_UPDATE_CURRENT on an existing pendingintent (same intent and id) will simply refresh the current alarm schedule if it already exists. Alternatively, add the code suggested by Ralgha to check and see if you already created the pending intent and set the alarm, and then if not, set the pending intent and alarm schedule. Both methods will likely have the same impact on battery (negligible). What will cause significant drain is doing something on a frequent schedule. The fact that you only want to update every hour and not when the screen is off, your app will use barely any battery (assuming it is done with it's processing relatively quickly and cleans up after itself nicely)
http://developer.android.com/reference/android/app/AlarmManager.html#ELAPSED_REALTIME
ELAPSED_REALTIME
This alarm does not wake the device up; if it goes off while the device is asleep, it will not be delivered until the next time the device wakes up.
http://developer.android.com/reference/android/app/AlarmManager.html#setInexactRepeating%28int,%20long,%20long,%20android.app.PendingIntent%29
setInexactRepeating
These alarms are more power-efficient than the strict recurrences supplied by setRepeating(int, long, long, PendingIntent), since the system can adjust alarms' phase to cause them to fire simultaneously, avoiding waking the device from sleep more than necessary.
http://developer.android.com/reference/android/app/PendingIntent.html#FLAG_UPDATE_CURRENT
FLAG_UPDATE_CURRENT
...if the described PendingIntent already exists, then keep it but its replace its extra data with what is in this new Intent. This can be used if you are creating intents where only the extras change, and don't care that any entities that received your previous PendingIntent will be able to launch it with your new extras even if they are not explicitly given to it.
You can check to see if the alarm is already set before you set it, and you can also use a flag so the alarm won't be delivered until the device is awake.
if ( PendingIntent.getBroadcast( context, 0, updateIntent, PendingIntent.FLAG_NO_CREATE ) == null )
{
pendingIntent = PendingIntent.getBroadcast( context, 0, updateIntent, 0 );
getSystemService( ALARM_SERVICE ).setInexactRepeating( AlarmManager.RTC, System.currentTimeMillis(), AlarmManager.INTERVAL_HOUR, pendingIntent );
}
I would appreciate some guidance on how to deal with OS killing a long run service.
Business scenario:
Application records a BTT track which may last for several hours. It can also show the track on map together with relevant statistics.
The application user interface enables the user to start/stop track recording and view the real time track on a map.
After start track recording user can exit the application and turn screen off (to save power), and only a service will remain running to keep the recording update to database (notification shown), until the user starts again the activity and ask for stop recording, which results in service termination.
Issue:
After a variable time, which runs from 40 minutes to 1 hour and a half, the recording service gets killed without any warning. As BTT outings may take several hours, this result in track recording incomplete.
Some additional information:
Service is started with START_STICKY and acquires a PARTIAL_WAKE_LOCK, and runs in the same process as the main activity.
New locations are acquired (and recorded) at user defined rate from 1 second to several minutes.
I know from the Android documentation that this is the expected OS behavior for long running services.
Question:
What is the best architecture design approach to have a well behaved application that could satisfy the business scenario requirements?
I can think of a couple of options (and I don’t like any of them), but I would like guidance from someone how have already faced and solved similar issue:
Use broadcast receiver (ideally connected to Location Manager if that’s possible) to have the service only running when a new location
is acquired?
Do not enable the user to leave the main activity (resulting in pour user experience)?
Have an alarm broadcast receiver restarting the service if needed?
Thanks to all who could share some wisdom on this subject.
I have an app that does a very similar thing. I make sure the service keeps running by making it a foreground task. When I am ready to start running, I call this function, which also sets up a notification:
void fg() {
Notification notification = new Notification(R.drawable.logstatus,
"Logging On", System.currentTimeMillis());
Intent notificationIntent = new Intent(this, LoggerActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
notification.setLatestEventInfo(this, "Logger","Logger Running",
pendingIntent);
startForeground(1, notification);
}
and then to leave foreground mode when logging is finished:
stopForeground(true);
I must build an application with a GPS tracker running during about a day. I'm aware of similar questions in SO but I haven't found any answers to some questions I have.
-I need a GPS fix every 10 min, so I think the best way to do it is to start the location service, get a fix (or timeout) and stop the service (with removeUpdates()). How can I have an application (or service or whatever) running this cycle every 10min and be sure it will continue as long as there is some battery left (even if device goes to sleep, it should wake it up every 10min to get a fix)? Is using AlarmManager a good idea?
-Can I expect the battery to last one day with this method?
I've checked mytracks but the gps listener seems always on and the battery is expected to last no more than 5h.
I've also checked CWAC Location Poller but it does only removeUpdates() on timeout and restart the listener immediately. It also uses a wakelock while in my case I think an AlarmManager could be a better idea.
Any help/suggestion welcome
You are spot on with alarm manager I use
Intent serviceIntent = new Intent(this, TrackerService.class);
mPendingIntent = PendingIntent.getService(this, 0, serviceIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.cancel(mPendingIntent);
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(), interval, mPendingIntent);
in a similar app for getting network location
interval is ms between starting the service
the service starts up, gets the location and closes
this was MUCH more battery efficient that hanging around with an active service waiting for reports
that code i posted cancels the previous alarms first so you don't get more than 1 :)
You can check out Passive Receiver
It'll give you an location update whenever another the devices location gets updated - only works on 2.2 or later