-
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();
-
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
-
申请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延时发送一个消息,到达时间后去自动释放锁。
-
释放WakeLock锁
如果是通过acquire(long timeout)方法申请的超时锁,则会在到达时间后自动去释放,如果是通过acquire()方法申请的永久锁,则必须进行显式的释放,否则由于系统一直持有wakelock锁,将导致无法进入休眠状态,从而导致耗电过快等功耗问题。
02-07
5598
