【唤醒屏幕总结】: WakeLock under-locked target

时间:2025-01-31 09:00:56

最近线上的项目遇到了这样的错误

: WakeLock under-locked target
	at $(:2665)
	at $(:2627)
	at $(:86)
	at (:933)"

经过一顿查找资料分析,是由于设置了();默认计数形式唤醒屏幕,这种情况下还需要设置 (false); 不然的话,很容易引起以下异常:

: WakeLock under-locked

原理:

       acquire() 函数如下:

            public void acquire () {
                synchronized (mToken) {
                    if (!mRefCounted || mCount++ == 0) {
                        try {
                            (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 {
                            (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掉


这是我的唤醒屏幕工具类,有需要的可以直接使用

/**
 * Author : 马占柱
 * E-mail : mazhanzhu_3351@
 * Time   : 2021/9/22 15:46
 * Desc   : 保证在息屏状体下,CPU可以正常运行
 */
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 {
                //创建实例之前可能会有一些准备性的耗时工作
                (300);
                synchronized () {
                    if (instance == null) {//二次检查
                        instance = new PowerManagerUtil();
                    }
                }
            }
        } catch (Exception e) {
            ();
        }
        return instance;
    }

    /**
     * @param context
     * @return 判断屏幕是否处于点亮状态 true【亮屏】 false【息屏】
     */
    public boolean isScreenOn(final Context context) {
        try {
            Method isScreenMethod = ("isScreenOn", new Class[]{});
            PowerManager pm = (PowerManager) (POWER_SERVICE);
            boolean screenState = (Boolean) (pm);
            return screenState;
        } catch (Exception e) {
            return true;
        }
    }

    /**
     * 唤醒屏幕
     */
    @SuppressLint("InvalidWakeLockTag")
    public void wakeUpScreen(final Context context) {
        try {
            if (.SDK_INT >= .VERSION_CODES.M) {
                PowerManager pm = (PowerManager) (POWER_SERVICE);
                /*
                 * SCREEN_DIM_WAKE_LOCK     CPU:保持运转 屏幕:保持显示但可以是暗的 键盘灯:关闭
                 * SCREEN_BRIGHT_WAKE_LOCK  CPU:保持运转 屏幕:保持高亮 键盘灯:关闭
                 * FULL_WAKE_LOCK           CPU:保持运转 屏幕:保持高亮 键盘灯:点亮
                 * PARTIAL_WAKE_LOCK        CPU:保持运转 屏幕:可以关闭 键盘灯:可以关闭
                 *
                 * ACQUIRE_CAUSES_WAKEUP    强制使屏幕亮起,这种锁主要针对一些必须通知用户的操作【慎用,会导致锁屏情况下,来消息屏幕频繁亮起,体验不好!】
                 *                          不能和 PARTIAL_WAKE_LOCK 一起用
                 *
                 * ON_AFTER_RELEASE         在释放锁时回收activity的timer计时器【不能和 PARTIAL_WAKE_LOCK 一起用】
                 * */
                 mWakelock = (
                        PowerManager.PARTIAL_WAKE_LOCK
                                | PowerManager.SCREEN_DIM_WAKE_LOCK, TAG);
                /*
                 * /fengyeNom1/article/details/121373158【详解】
                 * 在通常的wakelock使用时,会报错:: WakeLock under-locked。
                 * 这是因为出现了上述release函数末尾if(mCount<0)的情,用 setReferenceCounted(false) 就可以解决这个问题。
                 * 这个函数的作用:是不是需要计算锁的数量?设置为false时,在release的时候,不管你acquire()了多少回,可以一次releaseWakeLock掉。
                 *
                 * 注意这个方法默认为true,意味着一个WakeLock调用acquire()多次,也必须release()多次才能释放,
                 * 如果释放次数比acquire()多,则抛出异常: : WakeLock under-locked
                 * */
                (false);
                ();
                if (()) {//如果已获得唤醒锁但尚未释放,则返回true。
                    ();
                }
                // FIXME: 注意:WakeLock的设置是 Activiy 级别的,不是针对整个Application应用的。所以application下有多个activity一定需要注意下!
            }
        } catch (Exception e) {

        }
    }

}