I have an Android Application that uses a Countdown Timer that lasts for around 2 days. What is the best method to avoid my Countdown Timer from being killed by the Android Application Manager even if the user enables a power saving mode or restarts their phone ? (Sorry if this is a senseless question to answer, for the reason that I am new to Android development.)
What is the best method to avoid my Countdown Timer from being killed by the Android Application Manager even if the user enables a power saving mode or restarts their phone ?
That is not possible. Moreover, it is very wasteful (tying up system RAM, spending CPU time). If you want to get control at a certain time in the future, use methods on AlarmManager (e.g., setAlarmClock()). If you want to find out how much time remains between now and that certain time in the future, find out the current time (e.g., System.currentTimeMillis()) and subtract that from the future time to calculate the difference in times. To handle a reboot, you would need to set up the AlarmManager again, by using a BroadcastReceiver set up to respond to ACTION_BOOT_COMPLETED.
Related
AlarmManager on API19 has the method setExact() to set an exact alarm.
Exact means --> If I set an alarm to 2:01 pm it will be triggered at 2:01 pm
On API 23 - Marhsmwallow (6.0) there is a new method setExactAndAllowWhileIdle(), but as of the reference it is not EXACT because it will trigger only every minute and in low power idle mode only every 15 minutes.
Exact != every 15 minutes :-)
So how can I achieve an exact alarm with AlarmManager in 6.0?
If a user adds a reminder or a calendar appointment and wants to be informed 10 minutes before the event it should show the alarm EXACT 10 minutes before the event. With setExactAndAllowWhileIdle() this seems is not possible.
Reference Link:
http://developer.android.com/reference/android/app/AlarmManager.html#setExactAndAllowWhileIdle(int, long, android.app.PendingIntent)
So how can I achieve an exact alarm with AlarmManager in 6.0?
You are welcome to try setAlarmClock(), as AFAIK it is unaffected by Doze mode. Otherwise, AlarmManager is not a viable option for you. Even having your app on the battery optimization whitelist will not help, as AlarmManager behavior does not change based on the whitelist.
You are welcome to use GCM, as a high-priority message should give you an opportunity to alert the user. This, of course, requires network connectivity.
The only offline solution that I am aware of — and that I am presently testing — is to have the user add your app to the battery optimization whitelist, then use a foreground service (to try to keep your process around), a ScheduledExecutorService (for the timing), and a partial WakeLock (to keep the CPU on). This will be fairly devastating to the user's battery.
Using setExactAndAllowWhileIdle() for a one-time alarm will fire exactly on the given time even in Doze idle mode. So this probably is the way to go.
Problems start, if you want to repeat the alarm at a rate of < 15 min (or set any other at a time < 15 min away from the last one), as this will not work in Doze idle mode, where such alarms are forced to the next 15 min or are executed when idle maintenance starts, which happens for about ten minutes first after 1 hour, then after another 2 hours, then after another 4 hours and so on.
- EDIT -
As of today Nov 17, Dianne Hackborn writes in this Post's comments:
"For what it's worth, the minimum time between while idle alarms will be changing to 9 minutes at some point relatively soon (even on devices running the current Marshmallow builds)."
This doesn't change anything fundamentally though.
Here are my discussion with Ian Lake on Google+!
setExactAndAllowWhileIdle() is exact and should work.
The 15 minutes time frame is wrong in the java doc.
I was trying to create an automation system running in the background. My frequency range was between 1-15 minutes. My wish was not to use a foreground service. By looking at the name of the method "setExactAndAllowWhileIdle", I thought that yeah it is safe to go with one-time alarms, scheduling the next one when done.
However, I couldn't find a way to run code in doze mode with alarms running more frequent than 15 minutes. Instead, I choose to start a foreground service when doze mode gets activated and stop that foreground service when phone awakes. User won't be seeing your foreground notification while using his/her phone. I don't care much about the ones in doze mode.
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if(intent.getAction().equals("android.os.action.DEVICE_IDLE_MODE_CHANGED")){
if (pm.isDeviceIdleMode()) {
//startAutomationForegroundService();
} else {
//stopAutomationForegroundService();
return;
}
AutomationReceiver.completeWakefulIntent(intent);
return;
}
}
You need to register "android.os.action.DEVICE_IDLE_MODE_CHANGED" intent filter into your WakefulBroadcastReceiver. Care putting it into manifest may not help.
I need to running thread every one second. But when application killed, the thread must be still alive.
My thread task is used for increment Unix Timestamp (that synchronized when the first time application running from our server time) by one every second. I need to create this task because in some device, date time can changed unpredictable (maybe low on battery, hard reset, dropped or something else).
My Activity must be get that Unix Timestamp value when it needed.
From SO, Alarm Manager is not a good choice,
I would recommend you not to use an AlarmManager for 30 seconds, as some have suggested. Because 30 seconds is too short. it will drain the battery. For AlarmManager use a minimum 1 minute with RTC.
Other people suggest using Timer Task or ScheduledExecutorService, what the best thread to fit my need?
Thanks.
You would never achieve that. Any process could be killed by System. And task running every seconds is horrible (like AlarmManager said).
One idea is: save your server time and device time such as SystemClock.elapsedRealtime() . (do not use System.currentTimeMillis() for this purpose. ... this is display time for user and can be changed by user or something).
When you need time later, get elapsedRealtime() again and compare with stored elapsedRealtime(), and add this diff to stored server time. You will get desired time.
Or simply ask current time to your server , depends on needs :).
If you want to care hard reset I think that you should have database on your server to manage the first time when user launches app.
Ever played Candy Crush? Know how you run out of lives and have to wait 30 minutes to regenerate a new life and up to a maximum of 5? That is idea I am trying to implement in my app but I am uncertain on how to have code running even when the user closes app and/or phone.
My question is how to have a timer constantly running in the background of phone until the timer hits X minutes. Would I use the Timer class for this? Because I am familiar with that class and already have a form of it implemented in my app.
There are two pieces to your question:
To actually have a timer running so that you have an action taken after a certain period of time, use the AlarmManager. This should only be used if you are going to proactively interrupt or notify the user.
Your scenario doesn't actually need a timer, and it's more efficient not to use one unnecessarily. Instead, store a timestamp. When your app is opened again, compare the current time to the timestamp and calculate the effect. In the regenerating-lives example, you'd compare timestamps, see that 100 minutes have passed, divide by 30 minutes, and add 3 lives (maybe keeping the extra 10 minute remainder).
If you want timer to run in background you may use AlarmManager. You can set Alarm at specified intervals or you can set it in service if you want single shot alarms. Also while using AlarmManager beware that if your phone goes down then all alarms you've set will be vanished. So take care that you are saving alarm times before phone goes off. Take a look at:
http://developer.android.com/reference/android/app/AlarmManager.html
While using AlarmManager, use correct PendingIntent flags or you could lose previous alarms. If you still want more information you can raise here or have a google.
I don't think you can keep a timer running for you application even when the application is closed. Here is an idea i think about:
You need to start a timer when the life is gone and your application is running.
On your application close event, save that timer value in a persistent storage such as file
On appliction start, read the timer value from the persistent storage, and restart the timer for the remaining time
Once timer expires, generate a new life.
Hope it helps!
I found this answer that might be of great help. Hope it helps others.
There are several different approaches.
You can make use of the System's AlarmManager.
You can make your own Service.
You can make your TimerObject persist.
Check the link for the complete answer and links.
For my application, I want to have a Notification sent to the user at a specified time. To do this, I have set up a Timer and the corresponding TimerTask.
To be sure the Notification will be sent to the user even if the phone is aslept, I have acquired a PARTIAL_WAKE_LOCK. The problem is that this method draws a lot of power from my battery (my application is responsible for more than 50% of all the power consumption at the end of the day).
Is there another way (a more power efficient one of course) to do what I want to do?
Thanks in advance for the time you will spend trying to help me.
> Is there another way (a more power efficient one of course) to
> [have a Notification sent to the user at a specified time]?
You can use an the android AlarmManager for this.
See Using AlarmManager to Schedule Activities on Android as a tutorial and example.
I've got a clock in my widget that I'm making and I want it to update every minute in sync with the system clock. ACTION_TIME_TICK seems like the perfect solution however much of my research says it's impossible in an AppWidget while others say there are workarounds but their very vague.
I'd prefer not to do an AlarmManager as I'd have to update very frequently to make sure that it changes minutes when the system clock changes minutes and that would drain the battery more.
Is there a workaround for ACTION_TIME_TICK or what's the best way to update every minute in sync with the system clock with minimal battery drain?
Is there a workaround for ACTION_TIME_TICK
ACTION_TIME_TICK can only be registered via registerReceiver() from something that is already running. In your case, that "something" would need to be a constantly-running Service, and that's generally an anti-pattern. Users and the OS can get rid of that service when desired.
I would find a way to lightly relax the "in sync with the system clock" requirement, then use AlarmManager. After all, Android is not a RTOS, so nothing will be "in sync with the system clock" in any guaranteed sense.
Using AlarmManager, you would specify the first alarm to be the "top" of the next minute, with a period of 60 seconds and setRepeating(). Or, you would set(), scheduled for the "top" of the next minute, then schedule the next one via set() as part of your own processing, if you think you can manually correct for drift better that way.
if you just need to display it when your app runs then just update it using asyncTask
but if you need it's value even in the background then using service would be the best idea