The pm
and keepScreenOn
variables are globally defined.
I grab the PowerManager.WakeLock in my OnCreate method:
pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
keepScreenOn = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_LOCK,"tpd");
in my onStart, onResume, and onRestart I grab the lock with
if (keepScreenOn == null) {
keepScreenOn = pm.newakeLock(PowerManager,SCREEN_BRIGHT_LOCK,"tpd");
}
keepScreenOn.acquire();
in my onDestroy, onPause, and onStop I release the lock with:
if (keepScreenOn != null) {
keepScreenOn.release();
keepScreenOn = null
}
After my app exits I get a failure screen and adb complains that
java.lang.Exception: WakeLock finalized while still held: tpd
Tracing shows that I released the lock before exit. What have I missed?
There is no way out of the app without crossing at least one of
onPause
, onStop
, or o开发者_运维问答nDestroy
. I can see that the app called
release()
as often as it called acquire() so even though the
wakelock is reference counted it should still have zero refs.
Ok I believe I found the problem.
The WakeLock is reference counted. That means that if a second acquire()
happens it will just bump the reference count. Every call to acquire()
needs to be protected by a call to isHeld()
as in:
if ((keepScreenOn != null) && // we have a WakeLock
(keepScreenOn.isHeld() == false)) { // but we don't hold it
keepScreenOn.acquire();
}
I had assumed that acquire()
on a lock I held did nothing so
multiple acquire()
calls caused the problem. Since the reference
count is not zero the GC throws an error.
I know this question is old, but keep in mind that WakeLocks are 'reference counted' by default. You can turn off reference counting using setReferenceCounted(boolean)
, see http://developer.android.com/reference/android/os/PowerManager.WakeLock.html#setReferenceCounted(boolean)
No, there is only one declaration at the global scope and all calls to the acquire() and release() occur in that scope. I println when they happen and the acquire() occurs once and the release occurs once.
精彩评论