Android卡住的部分wakelock

卡住的部分wakelock

部分wakelock是PowerManager API给用户提供的允许用户在黑屏后(不管是系统超时还是用户按下电源键)保持CPU运行的机制。应用通过调用acquire()和参数PARTIAL_WAKE_LOCK获得部分wakelock。如果你的应用获得了一个部分wakelock,一直在后台运行(对用户不可见),那么这个wakelock就卡住了。这种情况会耗尽电量,因为他会阻止设备进入低电状态。部分wakelock只应该在必要的时候使用,用完应立即释放。

如果你的应用有卡住wakelock的问题,你可以通过本文来发现和解决这一问题。

发现问题

你可能不知道自己的wakelock卡住了。如果你的应用发布了,Android vitals可以帮你发现问题。

Android vitals

当应用有卡住的wakelock时,Android vitals可以通过Play Console通知你的应用存在性能问题。Android vitals会报告wakelock卡住一小时,并至少满足下面一点时:

  • 至少累计消耗0.7%的电量会话
  • 至少后台消耗0.1%的电量会话

电量会话是两次充满电之间的部分。

意识到存在卡住wakelock的问题后,再定位问题。

解决问题

Wakelock是在早期的Android平台中引入的,随着时间的推移,很多之前需要用wakelock的情况,在新版本上有更好的功能代替了,像JobScheduler和Firebase JobDispatcher。这段为解决wakelock问题给出建议,但长期来看,还是要移植应用满足最好的联系。

找到用wakelock的地方,比如newWakeLock(int, String)或者WakefulBroadcastReceiver。一些建议:

  • 建议在wakelock标签中添加包,类和方法名,以便定位。更多建议:
    • 不要使用个人信息,例如,email帐号。否则,设备日志将把名字计为:_UNKNOWN。
    • 不要用程序获得类名或方法名,例如getName()方法,因为他们会被Proguard混淆。用硬编码字符串。
    • 不要在wakelock标签中添加计数器或统一标识符。系统不能统计同一个方法创建的wakelock,因为他们有统一的标识符。
  • 确保代码释放了所有获得过的wakelock。确保所有调用acquire()的都有对应的release()。下面的例子中wakelock因为异常没有被释放:

    void doSomethingAndRelease() throws MyException {
        mWakeLock.acquire();
        doSomethingThatThrows();
        mWakeLock.release();  
// does not run if an exception is thrown
    }

正确的版本是:

    void doSomethingAndRelease() throws MyException {

        try {

            mWakeLock.acquire();

            doSomethingThatThrows();

        } finally {

            mWakeLock.release();

        }

    }
  • 确保wakelock不用了马上回收。例如,如果你正在使用wakelock来完成后台任务,确保任务完成后wakelock马上被释放。如果持有wakelock时间超过使用时间,说明持有wakelock时间过长。

解决了上面的问题后,用下面的工具验证wakelock是否正确释放:

  • dumpsys – 设备系统服务状态信息工具。可以看电池服务信息,包含一系列wakelock信息。运行adb shell dumpsys power。
  • 电池历史 – 解析Andriod bug report输出,将其中电源使用部分转化成直观的图标的形式的工具。

最好的练习

一般来说,应用应该尽可能避免使用partial wakelock,因为他太容易引起耗电。之前需要partial wakelock的大部分情形,Android提供了新的替换API。还有一个情况需要使用partial wakelock,即关屏后听音乐。如果需要运行任务,考虑下面的替换方案:

  • 长时间运行的HTTP下载,考虑用DownloadManager。
  • 应用需要从外部服务器同步数据,考虑用sync adapter。
  • 如果应用定期执行后台服务,考虑用JobScheduler或者Firebase JobDispatcher或者WorkManager,目前还在阿尔法阶段。定期触发服务,请看Intelligent Job-Scheduling。

用这些API的好处就是系统会根据电池的状态批量或推迟这些操作。

如果必须使用部分wakelock,一定要注意一些建议:

  • 确保你的应用的一部分保持在前台。例如,如果需要一个服务,那么启动一个前台服务。这样可以提醒用户你的应用一直在运行。
  • 确保获得和释放wakelock的逻辑简单。当你的wakelock逻辑特别复杂的时候,比如跟状态机,计时器,执行池,回调,那么其中任何一点疏忽都可能导致wakelock持有时间过长。这些问题很难分析调试。

猜你喜欢

转载自blog.csdn.net/yubing1015/article/details/85261524
今日推荐