在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。

需要申请权限

  1.   
        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=falseWake 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=208Screen off timeout: 30000 msScreen 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=falseWake 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=208Screen off timeout: 5000 msScreen 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=208Screen off timeout: 30000 msScreen 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=falseWake 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=falseWake 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=208Screen off timeout: 30000 msScreen 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:

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=falseWake 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=208Screen off timeout: 30000 msScreen 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。

更多相关文章

  1. android 默认锁屏界面没有紧急呼救入口如何解决
  2. 【读书笔记】【Android开发艺术探索】第10章 Android(安卓)的消
  3. 详解Android(安卓)视频播放时停止后台运行的方法
  4. Android中AdapterView/Adapter的深度学习
  5. 2018-7月Android试题整理
  6. webkit for android 4.0 by mogoweb base off Jelly
  7. android中的事件类型分为按键事件和屏幕触摸事件
  8. Android(安卓)Studio 快捷键整理分享
  9. Android(安卓)中使用 APT

随机推荐

  1. Mac android studio真机调试步骤
  2. 浅谈Android常用控件
  3. android 设置listview item选中背景色
  4. Android(安卓)混淆代码问题总结
  5. Android――动画专题研究
  6. SDK3.0 组件属性
  7. android uiautomator自动化测试
  8. 【转】android:minSdkVersion 相关知识
  9. 自定义ListView中的分割线(转)
  10. Android中的多击事件