In an app I have to regularly sync data to a server which happens at a fixed interval (mostly) of 5mins.
I am using set() / setExact() depending upon if Build API >= 19. Now, for most of the time the alarm gets fired and does it's job but intermittently (even during daytime) the alarm isn't getting fired.
The alarm manager is passed a pendingIntent for an IntentService which does the sync work.
And in onHandleIntent I am also running my setSchedule() which in turn sets an alarm to get fired after 5 mins(same as above^).
Using Alarm Type of RTC_WAKEUP (until now; I've recently changed it to elasped realtime + wakeup and waiting on for some test results)and the HTTP connection and socket timeout of 30secs each. The device was not restarted in between the 48hrs+ (as a sample case) duration as I don't miss any captured data it's just that the sync alarm skips somehow.
I am starting to doubt if this is a wakelock issue :|
Has anyone faced any problem with Kitkat's setExact() ? AFAIK, the way it is (except for using the RTC/elasped realtime change) the current way shouldn't be skipping on the alarms.
Related
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/
I have a problem using setExactAndAllowOnIdle. In my AlarmReceiver class I just show simple notification that shows when alarm was triggered and set another, same alarm but hour after.(currentTimeMillis + 60*60*1000). When my phone is in use application works fine, alarms come exactly on time. But when I let it work for few alarms without waking device up, they start to trigger with few minutes delays, or sometimes even exactly on time I wake up my phone.
You probably mean setExactAndAllowWhileIdle().
You didn't tell on which OS are You testing it but probably it's because of Doze Mode.
NOTICE:
Neither setAndAllowWhileIdle() nor setExactAndAllowWhileIdle() can
fire alarms more than once per 9 minutes, per app.
So You can't use this method to set every alarm what probably You doing.
For more information You can go here:
https://developer.android.com/training/monitoring-device-state/doze-standby.html
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.
I have a independent clock created in my application. The clock runs as a different thread in the activity, starting from a base time set by me. I update the clock using the difference between the uptimemillis when I set the clock, and the current uptimemillis. But the uptimetimer, can be reset by Android, and is ever reset when Android reboot.
I only want to know if the uptime timer is reset, to know if the clock is still reliable.
How?
According to the documentation you can use SystemClock.elapsedRealtime()
elapsedRealtime():
Returns milliseconds since boot, including time spent in sleep.
This value will only be reset when the device is restarted. Listen to the broadcast boot_complete and you will know when that is.
The problem with the updateMillis() is clearly noted in the documentation:
uptimeMillis():
Returns milliseconds since boot, not counting time spent in deep sleep. Note: This value may get reset occasionally (before it would otherwise wrap around).
From how I understand the documentation, by using elapsedRealtime your users cannot manipulate your counter.
I have created an Android service which basically does the following:
schedule a task, using the ScheduledThreadPoolExecutor.schedule() method
when the schedule time is reached, the task is executed and a new schedule is started
Thus, the service continuously has a timer in place (except during execution of the task); sometimes 2 (independent) timers are in place, depending on the result of the task. The service should be running all the time and executes different tasks from time to time.
All seems to work ok (at least when running with DDMS), but after a while (something like an hour without connecting the device via DDMS) the timer tasks are not executed anymore. The only way to get it working again is either stopping and starting the service again or by connecting the device with DDMS (using Eclipse); waking up the device only does not trigger this.
It looks like, Android sets the service in a kind of sleep mode (service is still running when looking at the Active Services on the device).
My question is: how do I prevent this behavior and keep the service working all the time?
I did some research and I found something which theoretically could give a solution, by acquiring a (PARTIAL_WAKE_LOCK) WakeLock in the service, but as far as I understand, using this solution, I have to acquire the lock at the onStartService() method and release it at onDestroy(), meaning that I keep the lock during the lifetime of the service (which is forever); I suspect a battery drainage using this method.
Is there another way to accomplish the same?
I have solved the problem, thanks to the replies above.
I switched from the ScheduledPoolThreaExecutor() to the AlarmManager. Together with the RTC_WAKEUP type all triggers are handled now.
I did not use the IntentService, because my service has to do things in parallel based on alarms (and IntentService implements a queued solution). The original service, which was staying alive all the time in the original implementation, is now only created whenever an alarm is triggered.
I also have the impression (but that is only a gut feeling, not based on real measurements, that this new implementation (where the service is created when needed and is not alive all the time (waiting on timer evens), is even better for battery life of the device.
How often to you need to execute, and what do you mean by running all the time? I guess that you don't mean be executing all the time?
I have a service that does this, and it works quite well:
It schedules an alarm with the alarm manager. Acquires a wakelock when the alarm is triggered, performs some work, and then schedules a new alarm before releasing the wake lock.
Use IntentService for your service implementation and register pending intents with AlarmManager to trigger those intents on the time basis you need.
I have used wake locks in an app before and I did not need to release them in the onDestroy(),
I literally had the following and it worked perfectly:
onClockListener{
acquire wakelock
method call
}
otherOnClickListener{
release wakelock
other method call
}
Not sure if it will help much but it definitely wont help if I don't post anything :)