I have a widget that displays the current time and some other info, therefore it has to update once every minute. I am using an AlarmManager that triggers every minute and calls an IntentService that updates the widget. This solution works fine in Android versions prior to Oreo. On Oreo, this solution does not work - it looks like the AlarmManager is not firing. I have read that there is a TextClock control now that automatically updates the text to the current time but unfortunately this is not a solution since I need to draw other non-text information on the widget.
The alarm is set as follows:
if (android.os.Build.VERSION.SDK_INT >= 19) {
alarmManager.setExact(AlarmManager.RTC, timeInMillis(), intent);
} else {
alarmManager.setRepeating(AlarmManager.RTC, timeInMillis(), 1000 * 60, intent);
}
Note that the alarm is rescheduled every time it fires on android 19+ since it is not a repeating alarm.
Is there an alternative solution for the above to work in Android O and later?
If you are using simple TextViews to display the Clock, use a TextClock instead of TextView (added in API Level 17)
If you are using more complex Views (e.g. you draw a bitmap), you have to use a foreground service, which either uses explicit TIME_TICK receivers or Handlers to schedule the updates.
You have to show a foreground notification and if not properly implemented, it could drain a lot of battery...
Related
I have an alarm clock app on the play store that works very well on most of the devices , but unfortunately some devices report the alarm does not fire on the time adjusted and i concluded from research that there are some devices that restrict apps running in the background and kills alarm manager !
I have handled doze mode using the following code :
if (Build.VERSION.SDK_INT >= 23)
{
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeStamp, pendingIntent);
}
else if (Build.VERSION.SDK_INT >= 19)
{
alarmManager.setExact(AlarmManager.RTC_WAKEUP, timeStamp, pendingIntent);
}
else
{
alarmManager.set(AlarmManager.RTC_WAKEUP, timeStamp, pendingIntent);
}
However this seems not enough on some devices.
I have read that a foreground service can prevent the system from killing the app anyway , however i can't ensure this also since i don't have in hand the devices where the problem occurs.
I want to ensure my alarm works perfectly fine on all devices and handles all scenarios , so what are all possible things to do to make sure my app runs properly and is not killed by the system?
You should be using AlarmManagerCompat.setAlarmClock() to set a user visible alarm suitable for an alarm clock app. This API uses setAlarmClock() on API 21+, which as per its documentation:
these alarms will be allowed to trigger even if the system is in a low-power idle (a.k.a. doze) mode. The system may also do some prep-work when it sees that such an alarm coming up, to reduce the amount of background work that could happen if this causes the device to fully wake up -- this is to avoid situations such as a large number of devices having an alarm set at the same time in the morning, all waking up at that time and suddenly swamping the network with pending background work. As such, these types of alarms can be extremely expensive on battery use and should only be used for their intended purpose.
I am working on application which tracking user way to work and back to home. Application is based on widget (where are printing informations to user) and background service which checking localizations and cunting informations and displaying on widget.
Before Android 9 I used AlarmManager and background service to every couple of minutes checking user localization and printing informtions on widget.
In Android 9 there are Service limitations and I cannot repeat service no less then 15 minutes. 15 minutes is too much, some users can have 5 minutes in road to work or home.
I tried JobService, JobIntentService, AlarmManager and no one is working less then 15 minutes. Only Foreground Service is working but I cannot use it because user are not running activity, all is working in background using widget.
Has anybody have a idea is that possible to run service in background repeating in less then 15 minutes. Or maybe any other idea how to achieve my requirements?
I need every couple o minutes (1-5 minutes) checking user localizations and counting, then sending datas to widget view.
You can use a foreground service for this. You just need to start the service as a foreground service like this:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent);
} else {
context.startService(intent);
}
As soon as the service is started you need to call startForeground(int id, Notification notification).
That being said it can be nice to be aware of the issue at https://issuetracker.google.com/issues/76112072 .
Also take a look at the blog post at https://android-developers.googleblog.com/2018/12/effective-foreground-services-on-android_11.
They also seem to touch your use-case with tracking:
Passive location tracking is a bad use case for foreground services.
If the user has consented to being tracked, use the
FusedLocationProvider API to receive bundled location updates at
longer intervals
You probably don't need to have an up to date widget when the screen is off.
Backgroud
I am using AlarmManager and JobScheduler(=> API 21) to generate Notification at 11 am in the morning.
Issue
Suppose my device is turned off at 11 am. So Alarm will not go off and Notification is not generated for today. Now, when it will reboot. the alarm is set again for 11 am of next day using BroadCastReceiver on action.BOOT_COMPLETED.
I have explored Job Scheduler a bit and setPeriodic(ms) function is used to set a periodic job but does not allow to schedule a job at specific time.
(Google -> define schedule -> arrange or plan (an event) to take place at a particular time.).
Any pointer to workarounds to this use case. I would prefer native solution, though.
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.
Background
I'm currently developing an application for Android which revolves around an alarm that goes of on an user specified time. My intent for it is that it will be used for waking people up in the morning (and the following morning - aka repeating alarm). When the alarm goes of it will call an Activity that has a couple of options (such as snooze). I've got all of this working but I'm running in to a problem.
Problem
I'm using AlarmManager to handle my alarm needs. There is however something curious going on with the class (in my opinion). There are two adviced ways to handle the setting of the alarm time. Namely setInexactRepeating and setRepeating. The problem with these functions are:
setInexactRepeating is not very accurate. My tests have shown that this gets approximately activated at the specified time, which the documentation indicates, all be it rather vaguely;
the alarm will not fire before this time, but there may be a delay of almost an entire alarm interval before the first invocation of the alarm.
My tests show there is usually something of a 5 minute delay. On this answer the user has an average delay of approximately 12 minutes. This won't do, of course, for a system that is supposed to wake people up at their specified times.
setRepeating does trigger at the specified time. The docs specify however that as of API 19 that all repeating alarms are inexact. Which is exactly what I don't want.
As of API 19, all repeating alarms are inexact. Because this method has been available since API 3, your application can safely call it and be assured that it will get similar behavior on both current and older versions of Android.
There is a setExact method, but this is a bit too specific. Aside from that it does not give me the option to have a certain interval (for repeating the alarm daily). Edit: After trying to go with setExact I found that this would require me to move up to API 19 (currently on 15), which is something I would like to avoid.
Question
Am I using the wrong class for this system? To me it seems like it should be a legit usage, but reading through the docs has left me wondering. Is there perhaps another class which is better suited for this system?
You can separate before API 19 and after API 19. While setting alarm for the first time:
if (Build.VERSION.SDK_INT >= 19) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), mondayIntent);
} else {
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY * 7, mondayIntent);
}
When you catch the alarm:
if (Build.VERSION.SDK_INT >= 19) {
rescheduleAlarm();
}
You must set the alarm with
setexact
again in rescheduleAlarm.
Hope this helps.