【唤醒屏幕总结】java.lang.RuntimeException: WakeLock under-locked target

67 篇文章 2 订阅
11 篇文章 0 订阅

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

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掉


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

/**
 * Author : 马占柱
 * E-mail : mazhanzhu_3351@163.com
 * 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 {
                //创建实例之前可能会有一些准备性的耗时工作
                Thread.sleep(300);
                synchronized (PowerManagerUtil.class) {
                    if (instance == null) {//二次检查
                        instance = new PowerManagerUtil();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return instance;
    }

    /**
     * @param context
     * @return 判断屏幕是否处于点亮状态 true【亮屏】 false【息屏】
     */
    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);
                /*
                 * 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 一起用】
                 * */
                PowerManager.WakeLock mWakelock = pm.newWakeLock(
                        PowerManager.PARTIAL_WAKE_LOCK
                                | PowerManager.SCREEN_DIM_WAKE_LOCK, TAG);
                /*
                 * https://blog.csdn.net/fengyeNom1/article/details/121373158【详解】
                 * 在通常的wakelock使用时,会报错:java.lang.RuntimeException: WakeLock under-locked。
                 * 这是因为出现了上述release函数末尾if(mCount<0)的情,用 setReferenceCounted(false) 就可以解决这个问题。
                 * 这个函数的作用:是不是需要计算锁的数量?设置为false时,在release的时候,不管你acquire()了多少回,可以一次releaseWakeLock掉。
                 *
                 * 注意这个方法默认为true,意味着一个WakeLock调用acquire()多次,也必须release()多次才能释放,
                 * 如果释放次数比acquire()多,则抛出异常: java.lang.RuntimeException: WakeLock under-locked
                 * */
                mWakelock.setReferenceCounted(false);
                mWakelock.acquire();
                if (mWakelock.isHeld()) {//如果已获得唤醒锁但尚未释放,则返回true。
                    mWakelock.release();
                }
                // FIXME: 注意:WakeLock的设置是 Activiy 级别的,不是针对整个Application应用的。所以application下有多个activity一定需要注意下!
            }
        } catch (Exception e) {

        }
    }

}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值