赞
踩
在Android app开发中,为了让某个页面持续显示一定时间,需要设置亮屏代码。
常用的方法有四种,分别如下:
方法1:通过PowerManager获取wakelock。
方法2:在view中设置view.setKeepScreenOn(true);
方法3:设置WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON 和 setTurnScreenOn(true);
方法4:在xml中设置android:keepScreenOn="true"
方法1一般用在非activity、fragment,无法操作UI界面的服务,如service、receiver。
需要申请权限
- PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- PowerManager.WakeLock wakeLock = pm.newWakeLock((PowerManager.SCREEN_BRIGHT_WAKE_LOCK
- | PowerManager.ACQUIRE_CAUSES_WAKEUP), "reminder:");
- //wakeLock.setReferenceCounted(false);
- wakeLock.acquire(6000L);
wakelock.acquire()不带参数的不建议使用,建议使用带参数的,带参数的系统会自动release,是比较安全的,即便是手动release后被系统handler自动释放,也不会出现crash。因为PowerManager有两个计数值,mInternalCount和mExternalCount,系统自动释放时不会操作mExternalCount。
- public void release(int flags) {
- synchronized (mToken) {
- if (mInternalCount > 0) {
- // internal count must only be decreased if it is > 0 or state of
- // the WakeLock object is broken.
- mInternalCount--;
- }
- if ((flags & RELEASE_FLAG_TIMEOUT) == 0) {
- mExternalCount--;
- }
- if (!mRefCounted || mInternalCount == 0) {
- mHandler.removeCallbacks(mReleaser);
- if (mHeld) {
- Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, mTraceName, 0);
- try {
- mService.releaseWakeLock(mToken, flags);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- mHeld = false;
- }
- }
- if (mRefCounted && mExternalCount < 0) {
- throw new RuntimeException("WakeLock under-locked " + mTag);
- }
- }
- }
但如果应用层手动执行release比acquire要多,且没有设置mRefCounted为true,系统就会抛异常。
其中wakeLock.setReferenceCounted(false);的作用是无论调用多少次acquire,只要最后执行了一次release就会释放wakelock,该值默认为true;
- WakeLock获取时相关的flag如下所示:
-
- PARTIAL_WAKE_LOCK :保持CPU 运转,屏幕和键盘灯有可能是关闭的。
- SCREEN_DIM_WAKE_LOCK :保持CPU 运转,允许保持屏幕显示但有可能是灰的,允许关闭键盘灯
- SCREEN_BRIGHT_WAKE_LOCK :保持CPU 运转,允许保持屏幕高亮显示,允许关闭键盘灯
- FULL_WAKE_LOCK :保持CPU 运转,保持屏幕高亮显示,键盘灯也保持亮度
- ————————————————
- 版权声明:本文为CSDN博主「llljjlj」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
- 原文链接:https://blog.csdn.net/llljjlj/article/details/80631664
在含有UI界面的activity、fragment中不推荐使用pm wakelock,推荐使用方法2和3。
- @RequiresApi(api = Build.VERSION_CODES.O_MR1)
- private void clearKeepScreenOnFlag() {
- Activity activity = getActivity();
- if (activity != null) {
- activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- activity.setTurnScreenOn(false);
- }
- }
-
- @RequiresApi(api = Build.VERSION_CODES.O_MR1)
- private void setKeepScreenOnFlag() {
- Activity activity = getActivity();
- if (activity != null) {
- activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- activity.setTurnScreenOn(true);
- }
- }
- 或者
- @Nullable
- @Override
- public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
- fragmentLayoutRoot=inflater.inflate(R.layout.fragment_dobreath_prepare, container, false);
- fragmentLayoutRoot.setKeepScreenOn(true);
- mHandler.postDelayed(mCleanKeepScreenTask,120*1000);
- return fragmentLayoutRoot;
- }
下面分析三种方式的功耗分析:
执行方法1.查看dumpsys power信息。
- private void wakeLockPm(Context context) {
- PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- PowerManager.WakeLock wakeLock = pm.newWakeLock((PowerManager.SCREEN_BRIGHT_WAKE_LOCK
- | PowerManager.ACQUIRE_CAUSES_WAKEUP), "reminder:");
- //wakeLock.setReferenceCounted(false);
- wakeLock.acquire(6000L);
- }
- $ adb shell dumpsys power | grep -i wake
- no_cached_wake_locks=true
- mWakefulness=Awake
- mWakefulnessChanging=false
- mWakeLockSummary=0x23
- mLastWakeTime=4321190 (82051 ms ago)
- mHoldingWakeLockSuspendBlocker=true
- mWakeUpWhenPluggedOrUnpluggedConfig=true
- mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig=false
- mDrawWakeLockOverrideFromSidekick=false
- mDoubleTapWakeEnabled=false
- Wake Locks: size=1
- SCREEN_BRIGHT_WAKE_LOCK 'reminder:' ACQUIRE_CAUSES_WAKEUP ACQ=-1s927ms (uid=10054 pid=8081)
- PowerManagerService.WakeLocks: ref count=1
- mGravitySensor={Sensor name="gravity Non-wakeup", vendor="qualcomm", version=1, type=9, maxRange=1.0, resolution=0.1, power=0.515, minDelay=20000}
-
- lingx@MI-20170703YUWL MINGW64 /e/watch/Apps/fitness (master)
- $ adb shell dumpsys power | grep -i screen
- mLastScreenBrightnessBoostTime=0 (4406128 ms ago)
- mScreenBrightnessBoostInProgress=false
- mSuspendWhenScreenOffDueToProximityConfig=true
- mDozeAfterScreenOff=false
- mMinimumScreenOffTimeoutConfig=5000
- mMaximumScreenDimDurationConfig=1000
- mMaximumScreenDimRatioConfig=0.20000005
- mScreenOffTimeoutSetting=30000
- mMaximumScreenOffTimeoutFromDeviceAdmin=9223372036854775807 (enforced=false)
- mScreenBrightnessSetting=0
- mScreenBrightnessModeSetting=1
- mScreenBrightnessOverrideFromWindowManager=-1
- mDozeScreenStateOverrideFromDreamManager=0
- mDozeScreenBrightnessOverrideFromDreamManager=-1
- mScreenBrightnessSettingMinimum=10
- mScreenBrightnessSettingMaximum=254
- mScreenBrightnessSettingDefault=208
- Screen off timeout: 30000 ms
- Screen dim duration: 1000 ms
- SCREEN_BRIGHT_WAKE_LOCK 'reminder:' ACQUIRE_CAUSES_WAKEUP ACQ=-4s813ms (uid=10054 pid=8081)
-
-
上面设置的是wakelock 6秒后自动释放,释放后再看信息
- lingx@MI-20170703YUWL MINGW64 /e/watch/Apps/fitness (master)
- $ adb shell dumpsys power | grep -i wake
- no_cached_wake_locks=true
- mWakefulness=Asleep
- mWakefulnessChanging=false
- mWakeLockSummary=0x0
- mLastWakeTime=4321190 (177007 ms ago)
- mHoldingWakeLockSuspendBlocker=false
- mWakeUpWhenPluggedOrUnpluggedConfig=true
- mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig=false
- mDrawWakeLockOverrideFromSidekick=false
- mDoubleTapWakeEnabled=false
- Wake Locks: size=0
- PowerManagerService.WakeLocks: ref count=0
- mGravitySensor={Sensor name="gravity Non-wakeup", vendor="qualcomm", version=1, type=9, maxRange=1.0, resolution=0.1, power=0.515, minDelay=20000}
-
- lingx@MI-20170703YUWL MINGW64 /e/watch/Apps/fitness (master)
- $ adb shell dumpsys power | grep -i screen
- mLastScreenBrightnessBoostTime=0 (4501875 ms ago)
- mScreenBrightnessBoostInProgress=false
- mSuspendWhenScreenOffDueToProximityConfig=true
- mDozeAfterScreenOff=false
- mMinimumScreenOffTimeoutConfig=5000
- mMaximumScreenDimDurationConfig=1000
- mMaximumScreenDimRatioConfig=0.20000005
- mScreenOffTimeoutSetting=30000
- mMaximumScreenOffTimeoutFromDeviceAdmin=9223372036854775807 (enforced=false)
- mScreenBrightnessSetting=0
- mScreenBrightnessModeSetting=1
- mScreenBrightnessOverrideFromWindowManager=-1
- mDozeScreenStateOverrideFromDreamManager=0
- mDozeScreenBrightnessOverrideFromDreamManager=-1
- mScreenBrightnessSettingMinimum=10
- mScreenBrightnessSettingMaximum=254
- mScreenBrightnessSettingDefault=208
- Screen off timeout: 5000 ms
- Screen dim duration: 1000 ms
使用wakelock可以加tag,方便功耗分析定位问题。
使用该方法的风险在于,必须有正确配对的release方式才不会功耗异常,若没有地方释放就会一直亮屏耗电。如果是在activity中使用,即便是activity 页面pause了,也不会自动release,所以应该尽量避免使用walock的方式。
- fragmentLayout.setKeepScreenOn(true);
- lingx@MI-20170703YUWL MINGW64 /e/watch/Apps/fitness (master)
- $ adb shell dumpsys power | grep -i screen
- mLastScreenBrightnessBoostTime=0 (5352101 ms ago)
- mScreenBrightnessBoostInProgress=false
- mSuspendWhenScreenOffDueToProximityConfig=true
- mDozeAfterScreenOff=false
- mMinimumScreenOffTimeoutConfig=5000
- mMaximumScreenDimDurationConfig=1000
- mMaximumScreenDimRatioConfig=0.20000005
- mScreenOffTimeoutSetting=30000
- mMaximumScreenOffTimeoutFromDeviceAdmin=9223372036854775807 (enforced=false)
- mScreenBrightnessSetting=0
- mScreenBrightnessModeSetting=1
- mScreenBrightnessOverrideFromWindowManager=-1
- mDozeScreenStateOverrideFromDreamManager=0
- mDozeScreenBrightnessOverrideFromDreamManager=-1
- mScreenBrightnessSettingMinimum=10
- mScreenBrightnessSettingMaximum=254
- mScreenBrightnessSettingDefault=208
- Screen off timeout: 30000 ms
- Screen dim duration: 1000 ms
- SCREEN_BRIGHT_WAKE_LOCK 'WindowManager' ON_AFTER_RELEASE ACQ=-23s285ms (uid=1000 pid=1400 ws=WorkSource{10054})
-
- lingx@MI-20170703YUWL MINGW64 /e/watch/Apps/fitness (master)
- $ adb shell dumpsys power | grep -i wake
- no_cached_wake_locks=true
- mWakefulness=Awake
- mWakefulnessChanging=false
- mWakeLockSummary=0x23
- mLastWakeTime=5285832 (69745 ms ago)
- mHoldingWakeLockSuspendBlocker=true
- mWakeUpWhenPluggedOrUnpluggedConfig=true
- mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig=false
- mDrawWakeLockOverrideFromSidekick=false
- mDoubleTapWakeEnabled=false
- Wake Locks: size=1
- SCREEN_BRIGHT_WAKE_LOCK 'WindowManager' ON_AFTER_RELEASE ACQ=-26s761ms (uid=1000 pid=1400 ws=WorkSource{10054})
- PowerManagerService.WakeLocks: ref count=1
- mGravitySensor={Sensor name="gravity Non-wakeup", vendor="qualcomm", version=1, type=9, maxRange=1.0, resolution=0.1, power=0.515, minDelay=20000}
执行view.setkeepScreenon(true)不受抬腕影响。view pause或destroy时,会自动释放SCREEN_BRIGHT_WAKE_LOCK,推荐使用这种方式。
方法3:
- 在activity中执行
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- setTurnScreenOn(true);
- $ adb shell dumpsys power | grep -i wake
- no_cached_wake_locks=true
- mWakefulness=Awake
- mWakefulnessChanging=false
- mWakeLockSummary=0x23
- mLastWakeTime=5636910 (28381 ms ago)
- mHoldingWakeLockSuspendBlocker=true
- mWakeUpWhenPluggedOrUnpluggedConfig=true
- mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig=false
- mDrawWakeLockOverrideFromSidekick=false
- mDoubleTapWakeEnabled=false
- Wake Locks: size=1
- SCREEN_BRIGHT_WAKE_LOCK 'WindowManager' ON_AFTER_RELEASE ACQ=-22s316ms (uid=1000 pid=1400 ws=WorkSource{10054})
- PowerManagerService.WakeLocks: ref count=1
- mGravitySensor={Sensor name="gravity Non-wakeup", vendor="qualcomm", version=1, type=9, maxRange=1.0, resolution=0.1, power=0.515, minDelay=20000}
-
- lingx@MI-20170703YUWL MINGW64 /e/watch/Apps/fitness (master)
- $ adb shell dumpsys power | grep -i screen
- mLastScreenBrightnessBoostTime=0 (5670577 ms ago)
- mScreenBrightnessBoostInProgress=false
- mSuspendWhenScreenOffDueToProximityConfig=true
- mDozeAfterScreenOff=false
- mMinimumScreenOffTimeoutConfig=5000
- mMaximumScreenDimDurationConfig=1000
- mMaximumScreenDimRatioConfig=0.20000005
- mScreenOffTimeoutSetting=30000
- mMaximumScreenOffTimeoutFromDeviceAdmin=9223372036854775807 (enforced=false)
- mScreenBrightnessSetting=0
- mScreenBrightnessModeSetting=1
- mScreenBrightnessOverrideFromWindowManager=-1
- mDozeScreenStateOverrideFromDreamManager=0
- mDozeScreenBrightnessOverrideFromDreamManager=-1
- mScreenBrightnessSettingMinimum=10
- mScreenBrightnessSettingMaximum=254
- mScreenBrightnessSettingDefault=208
- Screen off timeout: 30000 ms
- Screen dim duration: 1000 ms
- SCREEN_BRIGHT_WAKE_LOCK 'WindowManager' ON_AFTER_RELEASE ACQ=-27s602ms (uid=1000 pid=1400 ws=WorkSource{10054})
效果与方法2相同,activity pause后自动释放,再次resume自动screen_bright_wake_lock。
为了避免用户误操作到该页面长时间亮屏耗电,建议加入超时释放逻辑。
方法4:
- <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:keepScreenOn="true"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- </android.support.constraint.ConstraintLayout>
- lingx@MI-20170703YUWL MINGW64 /e/watch/Apps/fitness (master)
- $ adb shell dumpsys power | grep -i wake
- no_cached_wake_locks=true
- mWakefulness=Awake
- mWakefulnessChanging=false
- mWakeLockSummary=0x23
- mLastWakeTime=5733001 (174149 ms ago)
- mHoldingWakeLockSuspendBlocker=true
- mWakeUpWhenPluggedOrUnpluggedConfig=true
- mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig=false
- mDrawWakeLockOverrideFromSidekick=false
- mDoubleTapWakeEnabled=false
- Wake Locks: size=1
- SCREEN_BRIGHT_WAKE_LOCK 'WindowManager' ON_AFTER_RELEASE ACQ=-8s160ms (uid=1000 pid=1400 ws=WorkSource{10054})
- PowerManagerService.WakeLocks: ref count=1
- mGravitySensor={Sensor name="gravity Non-wakeup", vendor="qualcomm", version=1, type=9, maxRange=1.0, resolution=0.1, power=0.515, minDelay=20000}
- lingx@MI-20170703YUWL MINGW64 /e/watch/Apps/fitness (master)
- $ adb shell dumpsys power | grep -i screen
- mLastScreenBrightnessBoostTime=0 (5909168 ms ago)
- mScreenBrightnessBoostInProgress=false
- mSuspendWhenScreenOffDueToProximityConfig=true
- mDozeAfterScreenOff=false
- mMinimumScreenOffTimeoutConfig=5000
- mMaximumScreenDimDurationConfig=1000
- mMaximumScreenDimRatioConfig=0.20000005
- mScreenOffTimeoutSetting=30000
- mMaximumScreenOffTimeoutFromDeviceAdmin=9223372036854775807 (enforced=false)
- mScreenBrightnessSetting=0
- mScreenBrightnessModeSetting=1
- mScreenBrightnessOverrideFromWindowManager=-1
- mDozeScreenStateOverrideFromDreamManager=0
- mDozeScreenBrightnessOverrideFromDreamManager=-1
- mScreenBrightnessSettingMinimum=10
- mScreenBrightnessSettingMaximum=254
- mScreenBrightnessSettingDefault=208
- Screen off timeout: 30000 ms
- Screen dim duration: 1000 ms
- SCREEN_BRIGHT_WAKE_LOCK 'WindowManager' ON_AFTER_RELEASE ACQ=-10s177ms (uid=1000 pid=1400 ws=WorkSource{10054})
从现象看与方法2、3效果相同。但实际使用有很大区别,因为在xml中设置了keepScreenOn=true,在代码中执行getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setTurnScreenOn(false);
后发现SCREEN_BRIGHT_WAKE_LOCK并未释放。因此只有当确定本页面显示时不会被息屏才能在xml中配置亮屏,例如一个闪屏页面,过度页面,这些页面一般持续时间不能太长。
综上所述:
1. 如果是在receiver、broadcast中亮屏、唤醒cpu,只能使用wakelock,建议使用wakelock.acquire(xxxx)带参数的。
必须有地方释放wakelock,否则会持续亮屏、cpu活跃会对功耗有较大影响。
2. 如果是在activity、fragment等包含view 资源的页面中亮屏,建议使用方法2、3,设置view.setKeepScreenOn(true);
或者设置WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON 和 setTurnScreenOn(true);
3.如果是闪现过度页面,可以使用方法4在xml中配置keepScreenOn=true,因为这类页面持续时间短,也不需要考虑自动释放机制。
方法234所显示的页面,只要页面退到后台后都会自动释放SCREEN_BRIGHT_WAKE_LOCK。所以在包含view的页面中,尽量避免方法1。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。