遵循唤醒锁定最佳实践

使用唤醒锁定可能会影响设备性能。如果您需要使用唤醒锁定,请务必正确使用。本文档介绍了一些最佳实践,可帮助您避免常见的唤醒锁陷阱。

正确命名唤醒锁定

我们建议您在唤醒锁定标记中包含软件包、类或方法名称。这样一来,如果发生错误,您就可以更轻松地在源代码中找到创建唤醒锁的位置。下面提供了更多相关提示:

  • 在名称中省去任何个人身份信息 (PII),例如电子邮件地址。如果设备在唤醒锁定标记中检测到个人身份信息 (PII),则会记录 _UNKNOWN,而不是您指定的标记。
  • 请勿以编程方式(例如通过调用 getName())获取类或方法名称。如果您尝试以编程方式获取名称,Proguard 等工具可能会对其进行混淆处理。您可以改用硬编码字符串。
  • 请勿向唤醒锁定标签添加计数器或唯一标识符。创建唤醒锁的代码应在每次运行时使用相同的标记。通过这种做法,系统可以汇总每个方法的唤醒锁用量。

确保您的应用在前台显示

唤醒锁定处于活动状态时,设备会使用电量。设备的用户应知晓此情况。因此,如果您使用唤醒锁定,则应向用户显示一些通知。在实际操作中,这意味着您应在前台服务中获取并保持唤醒锁。前台服务需要显示通知。

如果前台服务不适合您的应用,您可能也不应使用唤醒锁。如需了解在应用不在前台运行时执行工作的一些其他方法,请参阅选择合适的 API 以保持设备唤醒文档。

保持逻辑简单

确保获取和释放唤醒锁定的逻辑尽可能简单。当唤醒锁定逻辑与复杂的状态机、超时、执行器池或回调事件关联时,该逻辑中的任何细微 bug 都可能导致唤醒锁定的保持时间超出预期。这些 bug 很难诊断和调试。

检查唤醒锁定是否始终会释放

如果您使用唤醒锁定,则必须确保正确释放您获取的每个唤醒锁定。这并不总是像听起来那么简单。例如,以下代码存在问题:

Kotlin

@Throws(MyException::class)
fun doSomethingAndRelease() {
    wakeLock.apply {
        acquire()
        doTheWork() // can potentially throw MyException
        release()   // does not run if an exception is thrown
    }
}

Java

void doSomethingAndRelease() throws MyException {
    wakeLock.acquire();
    doTheWork();         // can potentially throw MyException
    wakeLock.release();  // does not run if an exception is thrown
}

这里的问题是,方法 doTheWork() 可能会抛出异常 MyException。如果发生这种情况,doSomethingAndRelease() 方法会将异常传播到外部,并且永远不会到达 release() 调用。结果是,唤醒锁定已获取但未释放,这是非常糟糕的。

在更正后的代码中,即使抛出异常,doSomethingAndRelease() 也会确保释放唤醒锁:

Kotlin

@Throws(MyException::class)
fun doSomethingAndRelease() {
    wakeLock.apply {
        try {
            acquire()
            doTheWork()
        } finally {
            release()
        }
    }
}

Java

void doSomethingAndRelease() throws MyException {
    try {
        wakeLock.acquire();
        doTheWork();
    } finally {
        wakeLock.release();
    }
}