最近线上的项目遇到了这样的错误
java.lang.RuntimeException: WakeLock under-locked target at android.os.PowerManager$WakeLock.release(PowerManager.java:2665) at android.os.PowerManager$WakeLock.release(PowerManager.java:2627) at com.driving.driver.android.kepplive.PowerManagerUtil$1.run(PowerManagerUtil.java:86) at java.lang.Thread.run(Thread.java:933)"
经过一顿查找资料分析,是由于设置了mWakelock.acquire();默认计数形式唤醒屏幕,这种情况下还需要设置 mWakelock.setReferenceCounted(false); 不然的话,很容易引起以下异常:
java.lang.RuntimeException: WakeLock under-locked
原理:
acquire() 函数如下:
public void acquire () {
synchronized (mToken) {
if (!mRefCounted || mCount++ == 0) {
try {
mService.acquireWakeLock(mFlags, mToken, mTag);
} catch (RemoteException e) {
}
mHeld = true;
}
}
}
release() 函数如下:
public void release () {
release(0);
}
public void release ( int flags){
synchronized (mToken) {
if (!mRefCounted || --mCount == 0) {
try {
mService.releaseWakeLock(mToken, flags);
} catch (RemoteException e) {
}
mHeld = false;
}
if (mCount < 0) {
throw new RuntimeException("WakeLock under-locked " + mTag);
}
}
}
看到了吗?报错就抱在release(int flags)中,mCount为负数了,抛除了异常
我们再看下:setReferenceCounted(boolean flags);
public void setReferenceCounted(boolean value){
mRefCounted = value;
}
这个函数的作用是是不是需要计算锁的数量,设置为false时,在release()的时候,不管你acquire()了多少回,可以releaseWakeLock掉
这是我的唤醒屏幕工具类,有需要的可以直接使用
public class PowerManagerUtil {
public static final String TAG = "PowerManagerUtil";
//使用volatile关键字保其可见性
volatile private static PowerManagerUtil instance = null;
private PowerManagerUtil() {
}
public static PowerManagerUtil getInstance() {
try {
if (instance != null) {//懒汉式
} else {
//创建实例之前可能会有一些准备性的耗时工作
Thread.sleep(300);
synchronized (PowerManagerUtil.class) {
if (instance == null) {//二次检查
instance = new PowerManagerUtil();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return instance;
}
public boolean isScreenOn(final Context context) {
try {
Method isScreenMethod = PowerManager.class.getMethod("isScreenOn", new Class[]{});
PowerManager pm = (PowerManager) context.getSystemService(POWER_SERVICE);
boolean screenState = (Boolean) isScreenMethod.invoke(pm);
return screenState;
} catch (Exception e) {
return true;
}
}
@SuppressLint("InvalidWakeLockTag")
public void wakeUpScreen(final Context context) {
try {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
PowerManager pm = (PowerManager) context.getSystemService(POWER_SERVICE);
PowerManager.WakeLock mWakelock = pm.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK
| PowerManager.SCREEN_DIM_WAKE_LOCK, TAG);
mWakelock.setReferenceCounted(false);
mWakelock.acquire();
if (mWakelock.isHeld()) {//如果已获得唤醒锁但尚未释放,则返回true。
mWakelock.release();
}
// FIXME: 注意:WakeLock的设置是 Activiy 级别的,不是针对整个Application应用的。所以application下有多个activity一定需要注意下!
}
} catch (Exception e) {
}
}
}



