Even after a lot of research I am still not completely sure if the way how I implement a WakeLock
for a Service
started by a BroadcastReceiver
is correct - even though it seems to work fine. The broadcast receiver gets intents sent to it from an alarm, so to start with, from the API docs of AlarmManager
:
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.
So, in onReceive()
I do:
Intent serviceIntent = new Intent(context, SomeService.class); context.startService(serviceIntent); if(SomeService.wakeLock == null) { PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); SomeService.wakeLock = powerManager.newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, SomeService.WAKE_LOCK_TAG); } if(! SomeService.wakeLock.isHeld()) { SomeService.wakeLock.acquire(); }
and in the service I do:
try { // Do some work } finally { if(wakeLock != null) { if(wakeLock.isHeld()) { wakeLock.release(); } wakeLock = null; } }
The SomeService.wakeLock
field is package private, static and volatile.
What I am unsure about is the check using isHeld()
- does it really tell me if a WakeLock
is acquired or not, and do I need to do this check at all?
A wake lock is a mechanism to indicate that your application needs to have the device stay on. Any application using a WakeLock must request the android. permission. WAKE_LOCK permission in an <uses-permission> element of the application's manifest. Obtain a wake lock by calling PowerManager#newWakeLock(int, String) .
To release the wake lock, call wakelock. release() . This releases your claim to the CPU. It's important to release a wake lock as soon as your app is finished using it to avoid draining the battery.
A wakelock is a powerful concept in Android that allows the developer to modify the default power state of their device. The danger of using a wakelock in an application is that it will reduce the battery life of a device.
What I am unsure about is the check using
isHeld()
- does it really tell me if aWakeLock
is acquired or not, and do I need to do this check at all?
Actually slightly tricky to answer. Looking at the source for PowerManager
and PowerManager.WakeLock
here the WakeLock.acquire()
and WakeLock.acquireLocked()
methods are as follows...
public void acquire(long timeout) { synchronized (mToken) { acquireLocked(); mHandler.postDelayed(mReleaser, timeout); } } private void acquireLocked() { if (!mRefCounted || mCount++ == 0) { // Do this even if the wake lock is already thought to be held (mHeld == true) // because non-reference counted wake locks are not always properly released. // For example, the keyguard's wake lock might be forcibly released by the // power manager without the keyguard knowing. A subsequent call to acquire // should immediately acquire the wake lock once again despite never having // been explicitly released by the keyguard. mHandler.removeCallbacks(mReleaser); try { mService.acquireWakeLock(mToken, mFlags, mTag, mWorkSource); } catch (RemoteException e) { } mHeld = true; } }
...mService
is an IPowerManager
interface and the source for it isn't available so it's hard to tell what may or may not go wrong when attempting to call acquireWakeLock(...)
.
In any case, the only exception that can be caught is RemoteException
and the catch
block does nothing. Immediately after the try/catch, mHeld
is set true
regardless.
In short, if you call isHeld()
immediately after acquire()
the result will always be true
.
Looking further into the source for PowerManager.WakeLock
shows similar behaviour for release()
which calls release(int flags)
where the mHeld
member is always set to false
regardless of what happens.
In conclusion I'd suggest it is always a good idea to check isHeld()
just as a best practice in case later versions of Android change this behaviour of the WakeLock
methods.
Manage you wakeLock inside a singleton (unique instance accessible through all your context and object)
Use a singleton instance of a custom class, then you may get wakelock object reference from call to call ,
here an singleton example
class MyData { private static MyData mMydata= null; // unique reference ( singleton objet container) private PowerManager.Wakelock myobject = null; // inside the unique object container we have the unique working object to be use by the application // can't make instance from outside... we want to have single instance // we want that outside use method "getInstance" to be able to use the object private MyData() { } // retrieve and/or create new unique instance public static MyData getInstance() { if (mMydata == null) mMyData = new MyData(); return mMyData; } // Works with your memory stored object // get... public PowerManager.WakeLock getMyWakelock() { return myobject; } // set ... public void setMyWakeLock(PowerManager.WakeLock obj) { myobject = obj; } }
in your application to handle your "wakelock" object your may access it like
// set a created wakelock MyData.getInstance().setMyWakeLock(wl); // get the saved wakelock object PowerManager.WakeLock obj = MyData.getInstance().getMyWakeLock();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With