开发者

WakeLock finalized while still held

开发者 https://www.devze.com 2023-03-04 13:27 出处:网络
The pm and keepScreenOn variables are globally defined. I grab the PowerManager.WakeLock in my OnCreate method:

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消