I have a problem (that's why I'm here :P):
I am running a TimerTask and/or a Handler. They should do something every second, no matter if the screen is on or not (standby). The problem is, after some time (2 to 10 hours) this process becomes weird timed. Sometimes it takes 10 seconds, sometimes 4 hours etc.
Now, I've read that you can use a Partial Wake Lock to solve this issue. Tried it, but it has not solved my issue (Maybe you should know that another library is also using a WakeLock which gets released after some time, but mine never gets released by me).
Maybe you should also know that the task/runnable runs on an asynctask (so on it's own thread). The wakelock is created from outside.
Edit:
Maybe it's good to know that it's a device owner app. Also, I know of the battery drain problem, but I still need it. The app really has to process this every second. I just need a solution for it, any, no matter which.
Edit 2:
Here's my current WakeLock code, which is started when my custom application reaches onCreate. As I said, it is never released.:
PowerManager mgr = (PowerManager)getApplicationContext().getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"CustomWakeLock");
wakeLock.acquire();
Related
I'm developing an app that runs in the background, and does an API call every 5 minutes to download some data. I implemented a regular service with a Runnable in onStartCommand() that has a while(true) loop that runs forever. It has a Thread.sleep with a delay of 5 minutes in it.
I feel like this isn't the best way to do it (seems battery inefficient), but I'm not sure how else to do it. I'm also concerned about what would happen if the phone fell asleep. I read a bit on it, and read that I had to acquire partial wakelocks, but I'm not sure where I would put them in my code.
I need to alert the user of certain events by means of:
Vibration
Notification
The vibration should remain on indefinitely until the user ACKs the notification.
The problem is vibration stops when the device goes to sleep. I've read the following questions:
Allow phone to vibrate when screen turns off
Continue vibration even after the screen goes to sleep mode in Android
There was an answer to one of the above mentioned questions saying that vibrating without patterns did the trick. So I've tried calling the version of Vibrator.vibrate that accepts milliseconds instead of a pattern with a large number but the vibration stops anyway.
Other answers suggest to register a receiver on the ACTION_SCREEN_OFF action. This would allow me to resume vibration if the device goes to sleep after the alarm has started, but won't work if the device was already slept.
However, I could get the thing working if I were able to turn the screen on first, then register the receiver to deal with any screen off event that could happen from there on. So I've tried acquiring a full wake lock when the triggering event is received, before starting sound or vibration, but it does not work despite I'm using the flags FULL_WAKE_LOCK and ACQUIRE_CAUSES_WAKEUP. The wakeup part works, but soon after that the device goes to sleep again. I would like to think the FULL_WAKE_LOCK flag does not work because it has been deprecated in API 17, but my device is a Samsung running 4.1.2 which is API 16!
The recommended approach now seems to be using
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON but this should be called from an activity, and I don't have any screen up unless the user clicks in the notification, and if this happens the sound and vibration should already have been stopped.
So it looks like a dead-end.
What else could I try?
UPDATE:
I had no luck keeping the screen always on with wake locks, but on the other hand they allow me to turn the screen on if only for a few seconds. I actually don't need to keep the screen on, so I'm registering the receiver on the Intent.ACTION_SCREEN_OFF action, and when the screen goes off, the receiver resumes vibration again. This worked well in the Samsung, but I've now switched to a Huawei to continue testing and the receiver does not work.
UPDATE:
Here's the stack trace of the exception in the Huawei device:
java.util.NoSuchElementException: Death link does not exist
at android.os.BinderProxy.unlinkToDeath(Native Method)
at com.android.server.VibratorService.unlinkVibration(VibratorService.java:294)
at com.android.server.VibratorService.removeVibrationLocked(VibratorService.java:284)
at com.android.server.VibratorService.cancelVibrate(VibratorService.java:213)
at android.os.IVibratorService$Stub.onTransact(IVibratorService.java:83)
at android.os.Binder.execTransact(Binder.java:338)
at dalvik.system.NativeStart.run(Native Method)
Do you intend to let the device go to sleep or not? You can acquire a wakelock that wakes the screen on.
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
WakeLock wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "myTAG");
wl.acquire(LOCK_SCREEN_TIME_MINUTES * 60 * 1000);
That doesn't work for you?
After that you can show the notification, but I'm not sure of the effect, will it hold the vibrations. Above one works on GalaxyTab 2 with android 4.2.2 and HTC Hero with android 2.3.4.
After some testing I finally managed to get it working.
The Vibrator class hass two methods:
vibrate (long[] pattern, int repeat)
vibrate (long milliseconds)
The first one is the only way of vibrating indefinitely using the API (passing 0 as the second argument). But this has been proven to break in some devices (Huawei), as I posted in the question. I'm not talking about the vibration being stopped by the OS when the device goes to sleep, this had been dealt with using a receiver plus a wake lock as described in the question. I'm talking about exceptions, caused by a bugged implementation (the Vibrator class is abstract).
The second variant of this method does not accept a pattern, and does not allow indefinite vibration, but we can cheat this by passing a very large number of milliseconds as parameter. This works well in some devices (Huawei) as the answer I cited in the question correctly pointed, but does not work in others (Samsung), where the implementation has a default max value that will be used instead if the value passed as parameter exceeds it. This max value is actually less than a minute, and this means we can't rely on this approach.
So I went all out on this and created a Service, where I manually vibrate indefinitely like this:
while(vibrationActive){
Vibrator.vibrate(1000);
Thread.sleep(1000);
}
The receiver trick to detect when the screen goes off is no longer needed. Of course the OS keeps shutting down the vibrator when this happens, but the next iteration of the loop will resume vibration again. With this approach it is possible to create a sort of pattern as well, if the sleep time is greater than the vibration time, but again this pattern will be interrupted at any point if the screen goes off.
A dedicated service just to turn the vibrator on and off reliably. Can you believe it? About 150 lines of code (without the unit tests) for something that should have been possible with a few lines.
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.
Disclaimer: My app already working without any Wake Locks for 1+ year and all is well for most devices.
I'm tracking GPS and it works like this:
AlarmReceiver starts Service every 5/10/15 minutes (as user wishes)
Service subscribes for Location updates and waits MAX 1 minute for good GPS.
Wrap up, send data to server and shut down service.
Due to bad connections and bad locations - whole thing take up to 2-3 minutes sometimes. And it works. No matter if phone is sleeping or not.
Now I'm reading about WakeLock and it doesn't make sense to me. How come my stuff is working? Is that coincidence?
How come my stuff is working?
A combination of things, including a dollop of luck. :-)
First, as Joel noted, the device wakes up briefly courtesy of your alarm, but the OS is only guaranteed to hold a WakeLock for the duration of onReceive() of a BroadcastReceiver.
It is possible that, at least on some versions of Android, requesting GPS updates causes the OS to acquire its own WakeLock. This is undocumented behavior AFAIK, and I have never relied upon it personally. If it does, though, and you are doing the rest of your work ("Wrap up, send data to server and shut down service") before removing location updates, that would explain the behavior.
There are still potential gaps in your approach (e.g., if you delegate to a Service to do the work and are not holding a WakeLock as part of passing control to that service). Statistically speaking, it may fail occasionally but work a lot of the time.
Personally, I recommend using a WakeLock, in case the undocumented behavior changes. That's what I do in LocationPoller.
Well reading from the AlarmManager documentation..
The Alarm Manager holds a CPU wake lock as long as the alarm
receiver's onReceive() method is executing.
Further...
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.
So based on that.. I think it makes sense that it currently works; correct me if I'm wrong.
I'm using for my Android Service an Handler that reapeat some operation each 60 minutes (1 hour), with a PartialWakeLock to keep the phone not sleeping. But this cause a lot of battery usage.
So a decided to study about AlarmManager (i'm noob) that someone wrote here to be perfect for this kind of things..
But now reading along the web i find that who uses AlarmManager, still need a WakeLock. Is it true?
What is the best way to run a cycle each 60 minutes (1 hour), without kill the battery?
Thanx
P.S.
AlarmManager Android Developer
The Alarm Manager holds a CPU wake lock as long as the alarm
receiver's onReceive() method is executing. This guarantees that the
phone will not sleep until you have finished handling the broadcast.
Once onReceive() returns, the Alarm Manager releases this wake lock.
This means that the phone will in some cases sleep as soon as your
onReceive() method completes. If your alarm receiver called
Context.startService(), it is possible that the phone will sleep
before the requested service is launched. To prevent this, your
BroadcastReceiver and Service will need to implement a separate wake
lock policy to ensure that the phone continues running until the
service becomes available.
But so seems that i need 2 wakelock vs just 1 wakelock using handler....is it true?
I have made many test and this is the result:
-Alarm Manager save more battery than using handler+wakelock for long timing operation.
But you must use an additional wake lock to your activity/service started by the alarm, because the alarm manager wake lock doesn't cover it.
Even of this method uses two WakeLock the battery seems to be more efficient and with more life! During the tests (2days) the AlarmManager use 6 time less battery than other method. In my own case...
Hope this can help some one!
I suggest you to use AlarmManager to handle events with 1 hour interval.
Because we don't know exactly what you what to achieve we can't provide a more in deep answer/suggestion sorry.
I am not sure if it is still relevant,
but the answer is: using AlarmManager is preferred. You only need a WakeLock to keep phone running after AlarmManager has woken it up to send an Intent to your receiver and until service has finished its work. So phone will be awake only for a couple of milliseconds, compared to "all the time".