Right now, I am setting alarms like this:
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
timedate = cal.getTime();
//convert date to milis
long timeInMilis = (timedate.getTime());
//Set Alarm to Repeat
manager.setRepeating(AlarmManager.RTC_WAKEUP, timeInMilis, interval, pendingIntent);
Unfortunately, the scheduled times for repeating are inexact and I read that they could be inexact for a full interval!
So, I would like to switch over to seting an exact repeating alarm. My device requires a minimum only of the latest API 19/Android 4.4, so I can't use setRepeating.
What can I do instead to set an exact repeating alarm?
Unfortunately, the scheduled times for repeating are inexact and I read that they could be inexact for a full interval!
If your targetSdkVersion is 19 or higher, yes.
What can I do instead to set an exact repeating alarm?
Use setExact() to get control for your initial delay. Then, as part of your work for processing that event, use setExact() to get control at your next desired time. IOW, you do the "repeating" part yourself.
Yes, this is irritating.
It is intentionally irritating, to steer developers to not use exact repeating alarms, as those are worse for the battery than are their inexact brethren. If the user will perceive the inexact behavior and will not appreciate it, feel free to use setExact() to make the alarms occur when the user wants. However, if the user will not perceive the inexact behavior, please use inexact alarms, as the user may notice the battery impact of your exact alarms.
Related
Im creating a custom alarm app, and this means i have to run a piece of code (for example calling an Intent so it open a screen where i can stop the alarm). What is the best way to achieve this?
I tried it with the Alarm Manager and used
<receiver android:name=".receiver.AlarmReceiver"
android:process=":remote"></receiver>
in the Manifest File
In my code i call this
var alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(context, AlarmReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0)
alarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 10000, pendingIntent )
10000 because i wanted to test it, if it gets called after 10s
Is this the best way to do an alarm clockapp?
simple "yes" is too less for answer on SO, so I can only add that exact alarms are draining battery more than inexact, so use both types with respect to user. still, for alarm clock app broadcast calls should be exact, so go on with that solution
also, from doc:
Note: The Alarm Manager is intended for cases where you want to have your application code run at a specific time, even if your application is not currently running. For normal timing operations (ticks, timeouts, etc) it is easier and much more efficient to use Handler.
and also note a change since API19 (if you want to support such old):
Note: Beginning with API 19 (Build.VERSION_CODES.KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. There are new APIs to support applications which need strict delivery guarantees; see setWindow(int, long, long, android.app.PendingIntent) and setExact(int, long, android.app.PendingIntent). Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested.
Is there any way to schedule a notification to appear at a specific time?
I am developing an app that reminds a user to change their bandage every 6/12 hours and I wish to send a notification to the user 6/12 hours after they confirm that they have applied the bandage.
Is there any way to do this? I have tried to implement the alarmManager Class however every example I have found uses a specific time of the day as opposed to 6/12 hours after an event.
I have an app which checks whether to show a notification every 24 hours. You can change it to whatever interval you would like.
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
// Create a PendingIntent which AlarmManager would raise.
// You should have a BroadcastReceiver to receive the intent and send a push notification.
setInexactRepeating(
AlarmManager.RTC_WAKEUP,
startAt.toEpochSecond() * 1000,
intervalInMillis,
pendingIntent
)
}
startAt -> Epoch when your alarm should start working (preferably in future). If this is in past, it will immediately boradcast the intent.
intervalInMillis -> Interval in milliseconds. For your case this should be 6 hours.
If your app requires different alarms (notifications) at 6 and 12 hours, I would still go with 6 hours or even 3 hours as the interval. When the broadcast is received, you should check if the app is supposed to send a notification or not. If not, don't do anything.
Read more about Scheduling repeating alarms.
Note: AlarmManager is affected by doze mode and you need to reset all your alarms after the phone restarts. Clubbing this with WorkManager would be ideal. But this should get you started.
Schedule tasks with WorkManager
https://developer.android.com/topic/libraries/architecture/workmanager/
Previously firebase-jobdispatcher-android was working fine now google introduced new WorkManager for scheduling task.
Here is a simple implementaion
http://thetechnocafe.com/how-to-use-workmanager-in-android/
My app needs to update its data every 24hrs. The user should not be able to access some parts of the app if its out of date.
When the app starts up, I check if the database is out of date. But, the users might keep the app open of in the background for a long time, and I need to alert them when the update is required.
What's the best way to do this? My Initial thought was to use some kind of Handler thread and save a timestamp somewhere every time the app was paused, and then calculate the new time and restart the timer on resumer.
This leaves two questions:
How can I detect whenever my app is paused or resumed, regardless of activity?
And what is the best idiom for a long-running timer in Android? (keeping in mid that it has to be able to modify UI components ie show an alert when he time is up)
You could do that, but you should not, instead store the time stamp in the shared preferences whenever the app get closed, when open again read that value again and calculate the difference by getting the actual timestamp.... then after that update if necessary the lapsed time!
timeStamp is just a long value..
and you can get it by just calling the System.currentTimeMillis()
and for the shared preferences use the Class SharedPreferences
You can have a Service do the query every 24 hours for you and notify the user if it fails. You can use the AlarmManager for that. Eg:
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent m_intent = new Intent(this, YourService.class);
PendingIntent pi = PendingIntent.getService(this, 2, m_intent, 0);
alarm.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 1000 * 24 * 60 * 60, pi);
The Service can then ask the AlrmManager to call itself after 24 hours again using the above code only.
NOTE: Alarms can be cancelled by the system or the user (force stop). So, this solution comes with its caveats.
In my app I am trying to get the users current location and log it. The user can select an interval. Right now the logging is not happening consistently. Sometimes the logs are just off by a couple seconds and sometimes they are off by a few hours. Also if it is not logging and you turn the GPS off/on then it will start working again. The entire app is based around the idea that you will only be able to get your location using GPS when you use it. I have a few theories as to why this may be.
I am getting the logs by using AlarmManager setExact inside a broadcast receiver. I know that this is not guaranteed to be perfectly accurate and could possible account for a few seconds here and there.
I also know that the GPS can take some time to acquire. Is there a normal range for this time. I could see this taking up to a few minutes possibly but several hours seems like a lot.
I don't know a lot about loopers and am having some difficulty understanding them. I was wondering if the looper in the requestSingleUpdate could have anything to do with it
locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, this, Looper.myLooper());
I know loopers process tasks in the background using a queue and I was't sure if other tasks could get stuck on the queue in front of it causing delays.
My last theory is that it has something to do with not timing out while searching for the GPS signal. If I am searching for a signal every 10 seconds (the fastest allowed) but the phone cannot find a signal the AlarmManager will fire again and I will have two services trying to get a signal. I don't really understand how the services work under the hood so I don't know if this is a possibility or not.
If anyone has any ideas/resources and could point me in the right direction I would really appreciate it.
Here is the code. I can include more if that would be helpful.
#Override
public void onReceive(Context context, Intent intent) {
SharedPreferences pref = context.getSharedPreferences(SettingsActivity.PREFERENCES, Context.MODE_PRIVATE);
if(!pref.getBoolean(SettingsActivity.ARG_TRACK, true)){
return;
}
alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent alarmIntent = new Intent(context.getApplicationContext(), AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, 0);
long interval = pref.getLong(SettingsActivity.ARG_TRACKER_INTERVAL, 15000);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmMgr.setExact(AlarmManager.RTC_WAKEUP,System.currentTimeMillis()+interval, pendingIntent);
}else{
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
}
context.startService(new Intent(context.getApplicationContext(), AlarmService.class));
}
Inside my service I am calling LocationManager requestSingleUpdate()
locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, this, Looper.myLooper());
In my app I am trying to get the users current location and log it. The user can select an interval. Right now the logging is not happening consistently. Sometimes the logs are just off by a couple seconds and sometimes they are off by a few hours. Also if it is not logging and you turn the GPS off/on then it will start working again. The entire app is based around the idea that you will only be able to get your location using GPS when you use it. I have a few theories as to why this may be.
If i'm not wroing, in your scenario, the interval is not period of location provider. It's directly period of alarm. The story like that
User selects an interval(period), for example 10 minutes.
After 10 minutes(approximately), device wakes up and makes location request to receive single location.
In that case you are facing the gps provider's lag. So, each time when wake up, you are waiting the gps provider to be warm. This is why the logs aren't consistently.
I am getting the logs by using AlarmManager setExact inside a broadcast receiver. I know that this is not guaranteed to be perfectly accurate and could possible account for a few seconds here and there.
You are using exact settings for wake up. This is not actual reason of long lag.
I also know that the GPS can take some time to acquire. Is there a normal range for this time. I could see this taking up to a few minutes possibly but several hours seems like a lot.
You have to wait until GPS provider to be warm. This warming time could change by where you stay at this moment. If you are inside a building, takes long
I don't know a lot about loopers and am having some difficulty understanding them. I was wondering if the looper in the requestSingleUpdate could have anything to do with it
Simply, when you pass a thread's looper here, onLocationChanged() method will be used the looper. But you are already making single request. No more update will be fired. (In your scenario, each wake up is one single location request)
My last theory is that it has something to do with not timing out while searching for the GPS signal. If I am searching for a signal every 10 seconds (the fastest allowed) but the phone cannot find a signal the AlarmManager will fire again and I will have two services trying to get a signal. I don't really understand how the services work under the hood so I don't know if this is a possibility or not.
This is a problem of your scenario. If you set alarm with short period, it's so normal the next wake up could happen. You can follow below things
Due to wait until gps warm, make long alarm period at least 5 minutes
Make timeout scenario, for example wait 1 minute or more until receiving location.
If cant receive location in time, shutdown everything and wait the next wakeup.
Question about alarm manager
I have this code
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, 5);
Integer prof=t.getProfile();
String prof2=prof.toString();
Intent intent = new Intent(this, AlarmActivity.class);
intent.putExtra("prof",(String)prof2);
PendingIntent pendingIntent = PendingIntent.getActivity(this,(int)t.getId(), intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am =
(AlarmManager)getSystemService(Activity.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),
pendingIntent);
Its unfinished yet...
I know I can set time of the calendar with cal.set(Calendar.MINUTES,minutes); and same for hours..
But how do I set day? For example - monday?
day_of_week sets it? If so - range is 0-6 or 1-7? And lowest value is monday or sunday?
Also, if Im going to make repeating event (once a week) - should I make new calendar and set day of week/hours/minutes? or should I user getInstance() and change hour/min/day of week?
About alarm manager. When u make an alarm, you give request_code which
should be uniq. If I reboot my phone - does all the request codes stay
in alarm manager on phone? If no - how to make they stay... If yes -
how do I delete unnecesery made ones while testing?
You can also use:
cal.add(Calendar.DATE, 7)
to set a calendars time to one week from the current calendars setting (and subtract and so forth).
I think a link to the docs is probably warranted here:
http://developer.android.com/reference/java/util/Calendar.html
Regarding your second question, no alarm managers do not persist on phone reboot, you have to save them in shared prefs or SQL and then reload the alarms the next time the phone (and your app) restarts...
To cancel an alarm you use alarm.cancel(pendingIntent). The pendingIntents you need to keep track of on your own.
An example of how to set the calendar can be found here. Additionally, the Android Developer's API shows multiple methods on how to set the day