android WakeLock简介

  1. WakeLock机智
    WakeLock是android系统中一种锁的机制,只要有进程持有这个锁,系统就无法进入休眠状态。应用程序要申请WakeLock时,需要在清单文件中配置android.Manifest.permission.WAKE_LOCK 权限。
    根据作用时间,WakeLock可以分为永久锁和超时锁,永久锁表示只要获取了WakeLock锁,必须显式的进行释放,否则系统会一直持有该锁;超时锁表示在到达给定时间后,自动释放WakeLock锁,其实现原理为方法内部维护了一个Handler。
    根据释放原则,WakeLock可以分为计数锁和非计数锁,默认为计数锁,如果一个WakeLock对象为计数锁,则一次申请必须对应一次释放;如果为非计数锁,则不管申请多少次,一次就可以释放该WakeLock。以下代码为WakeLock申请释放示例,要申请WakeLock,必须有PowerManager实例,如下

    PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
    mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK|PowerManager.ACQUIRE_CAUSES_WAKEUP, "Fota");
    mWakeLock.acquire();
    mWakeLock.release();
    
  2. PowerManager中的WakeLock
    要获取、申请Wakelock时,直接通过PowerManager的WakeLock进行。它作为系统服务的接口来供应用调用。
    获取WakeLock对象获取WakeLock实例在PowerManager中进行。
    在应用中获取WakeLock对象,方式如下:

    PowerManager.WakeLock mWakeLock =  mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
    

    应用中获取wakelock对象,获取的是位于PowerManager中的内部类——WakeLock的实例,在PowerManager中看看相关方法:

    public WakeLock newWakeLock(int levelAndFlags, String tag) {
    	     validateWakeLockParameters(levelAndFlags, tag);
    	return new WakeLock(levelAndFlags, tag, mContext.getOpPackageName());
    }
    

    在PowerManager的newWakeLock()方法中,首先进行了参数的校验,然后调用WakeLock构造方法获取实例,构造方法如下:

    WakeLock(int flags, String tag, String packageName) {
        mFlags = flags;
        mTag = tag;
        mPackageName = packageName;
        mToken = new Binder();
        mTraceName = "WakeLock (" + mTag + ")";
    }
    

    除了构造方法中必须要传入的参数之外,还有如下几个属性:

    //表示内部计数
    private int mInternalCount;
    //表示内部计数
    private int mExternalCount;
    //表示是否是计数锁
    private boolean mRefCounted = true;
    //表示是否已经持有该锁
    private boolean mHeld;
    //表示和该wakelock相关联的工作源,这在当一个服务获取wakelock执行工作时很有用,以便计算工作成本
    private WorkSource mWorkSource;
    //表示一个历史标签
    private String mHistoryTag;
    

    Wakelock共有以下几种等级:

    //如果持有该类型的wakelock锁,则按Power键灭屏后,即使允许屏幕、按键灯灭,也不会释放该锁,CPU不会进入休眠状态
    public static final int PARTIAL_WAKE_LOCK;
    //Deprecated,如果持有该类型的wakelock锁,则使屏幕保持亮/Dim的状态,键盘灯允许灭,按Power键灭屏后,会立即释放
    public static final int SCREEN_DIM_WAKE_LOCK;
    //Deprecated,如果持有该类型的wakelock锁,则使屏幕保持亮的状态,键盘灯允许灭,按Power键灭屏后,会立即释放
    public static final int SCREEN_BRIGHT_WAKE_LOCK
    //Deprecated,如果持有该类型的wakelock锁,则使屏幕、键盘灯都保持亮,按Power键灭屏后,会立即释放
    public static final int FULL_WAKE_LOCK
    //如果持有该锁,则当PSensor检测到有物体靠近时关闭屏幕,远离时又亮屏,该类型锁不会阻止系统进入睡眠状态,比如
    //当到达休眠时间后会进入睡眠状态,但是如果当前屏幕由该wakelock关闭,则不会进入睡眠状态。
    public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK
    //如果持有该锁,则会使屏幕处于DOZE状态,同时允许CPU挂起,该锁用于DreamManager实现Doze模式,如SystemUI的DozeService
    public static final int DOZE_WAKE_LOCK
    //如果持有该锁,则会时设备保持唤醒状态,以进行绘制屏幕,该锁常用于WindowManager中,允许应用在系统处于Doze状态下时进行绘制
    public static final int DRAW_WAKE_LOCK
    

    这些值会在下面以图标的形式总结。除了等级之外,还有几个标记

    //该值为0x0000FFFF,用于根据flag判断Wakelock的级别,如:
    //if((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) == PowerManager.PARTIAL_WAKE_LOCK){}
    public static final int WAKE_LOCK_LEVEL_MASK
    //用于在申请锁时唤醒设备,一般情况下,申请wakelock锁时不会唤醒设备,它只会导致屏幕保持打开状态,如果带有这个flag,则会在申
    //请wakelock时就点亮屏幕,如常见通知来时屏幕亮,该flag不能和PowerManager.PARTIAL_WAKE_LOCE一起使用。
    public static final int ACQUIRE_CAUSES_WAKEUP
    //在释放锁时,如果wakelock带有该标志,则会小亮一会再灭屏,该flag不能和PowerManager.PARTIAL_WAKE_LOCE一起使用。
    public static final int ON_AFTER_RELEASE
    //和其他标记不同,该标记是作为release()方法的参数,且仅仅用于释放PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK类型的
    //锁,如果带有该参数,则会延迟释放锁,直到传感器不再感到对象接近
    public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY
    
  3. 申请WakeLock
    当获取到WakeLock实例后,就可以申请WakeLock了。前面说过了,根据作用时间,WakeLock锁可以分为永久锁和超时锁,根据释放原则,WakeLock可以分为计数锁和非计数锁。申请方式如下:

    PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
    PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Tag");
    wl.acquire();//申请一个永久锁
    Wl.acquire(int timeout);//申请一个超时锁
    
    acquire()方法源码如下:
    public void acquire() {
        synchronized (mToken) {
            acquireLocked();
        }
    }
    public void acquire(long timeout) {
        synchronized (mToken) {
            acquireLocked();
            //申请锁之后,内部会维护一个Handler去完成自动释放锁
            mHandler.postDelayed(mReleaser, timeout);
        }
    }
    

    可以看到这两种方式申请方式完全一样,只不过如果是申请一个超时锁,则会通过Handler延时发送一个消息,到达时间后去自动释放锁。

  4. 释放WakeLock锁
    如果是通过acquire(long timeout)方法申请的超时锁,则会在到达时间后自动去释放,如果是通过acquire()方法申请的永久锁,则必须进行显式的释放,否则由于系统一直持有wakelock锁,将导致无法进入休眠状态,从而导致耗电过快等功耗问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值