Update ongoing notification every 60 seconds - android

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

Related

How to debug an AlarmManager-activated service

I am implementing a widget that checks on-line train departure times between every minute and every hour, depending on the time of day.
Calling the service with
manager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() - 10000, 60000, pendingIntent)
works fine, but for debugging I would like to reduce the interval to about 10 seconds which cannot be done because of the 1-minute limit in more recent versions of Android. Clearly, I don't care about battery life in the emulator.
As far as I understand, using an Hander/Timer is not an option, because it required the task to be in the foreground. Is a visible widget "in the forground"?
What is the recommended practice in this case?
you actually have to tasks
configure the alarmmanager to add/remove trigger events via intents
interprete the events with intents in a service
If you seperate both you can easily create a very simple gui/activity that does the same as the alarmmanager would do when being triggerd and that you can debug:
* onSendButtonClick: create and send pendingIntent
for the alarmmanager-handling i would implement logging into a text file each time alarmmanager is added/removed/triggered.
Be prepared that newer android versions may postpone alarmmanager events to save energy until the device is already active and that intervals less than 15 minutes may not work.
you may also need on_boot_complete to reconfigure alarmmanager after device-shutdown

Efficiency of using AlarmManager to update App Widgets in Android

I have developed an App Widget that requires to be updated every 10 minutes. In Android documentation about App Widgets it is specified that if the widget needs to be updated more frequently than once per hour, it is recommended to use AlarmManager and set the alarm type to either RTC or ELAPSED_REALTIME so the alarm is only delivered when the device is awake.
I have implemented the AlarmManager and my widget is updating correctly every 10 minutes. After several testings, using both RTC and ELAPSED_REALTIME alarm types, I have seen that my widget is still getting updated after the device goes to sleep. I can see in LogCat that my widget is getting updated even after 30 minutes that the device went to sleep (30 minutes after the screen turns off).
My question is, if the alarm is still been delivered and my widget is updated every 10 minutes even after the device has gone to sleep how is using AlarmManager with RTC or ELAPSED_REALTIME as the documentation says more battery efficient than just setting 600,000 milliseconds for updatePeriodMillis property on my widget provider xml file?
A couple of things:
Both RTC and ELAPSE_REAL_TIME have WAKEUP and non WAKEUP versions, so if you do not want you widget updating when the phone is sleeping, you could chose the non WAKEUP version. If you set updatePeriodMillis, it is going to wake the device either way.
When you set your alarm using setInexactRepeating() instead of setRepeating(), Android will bundle multiple inexact alarms and fire them at the same time, which is more battery efficient. Also according to the doc:
As of API 19, all repeating alarms are inexact.
Another thing is that, according to the AppWidgetProviderInfo doc:
Updates requested with updatePeriodMillis will not be delivered more
than once every 30 minutes.
so it probably wouldn't be useful to you if you needed to update every 10 minutes.

Why is AlarmManager alarm delayed on first run?

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

Android does not execute everything on night

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

Everyday notifications at certain time

I would like to achieve this:
After first turning on the application, user receives notifications, every day at 2pm, if certain condition is true. If condition is false, we are not showing a notification this day. The condition is checked at 2pm, it downloads some data from the Internet.
So far I used AlarmManager and its method setRepeating() with 24h interval. AlarmManager fires up a Service. In this Service I'm downloading the data, checking condition and if it's true - showing Notification. Since downloading can last more than 5 seconds, I've declared android:process=":background" for this Service, to run it in separate process and not block my UI.
This approach has two drawbacks:
1: If user opens application let's say at 4pm (and the condition is true), he will receive the notification immediately. From setRepeating() documentation:
If the time occurs in the past, the alarm will be triggered
immediately, with an alarm count depending on how far in the past the
trigger time is relative to the repeat interval.
I would like that user will not receive a notification this day, only the next day and so on.
2: I'm worried that my notifications will not show after user switch the phone off. From AlarmManager documentation:
Registered alarms are retained while the device is asleep (and can optionally wake the device up if they go off during that time), but will be cleared if it is turned off and rebooted.
I don't know if it's possible to make it work all the time.
If you have any ideas how to make it better, you're welcome.
1: I'm not quite sure if i understood your question, but I think all you have to do is if it already is past 2pm add a day to 2pm:
GregorianCalendar twopm = new GregorianCalendar();
twopm.set(GregorianCalendar.HOUR_OF_DAY, 14);
twopm.set(GregorianCalendar.MINUTE, 0);
twopm.set(GregorianCalendar.SECOND, 0);
twopm.set(GregorianCalendar.MILLISECOND, 0);
if(twopm.before(new GregorianCalendar())){
twopm.add(GregorianCalendar.DAY_OF_MONTH, 1);
}
alarmManager.setRepeating(type, twopm.getTimeInMillis(), 1000*60*60*24, intent);
2: You could register a BroadcastReceiver for booting and start your alarm again there. Take a look at this: Android BroadcastReceiver on startup - keep running when Activity is in Background

Categories

Resources