Suivre les bonnes pratiques concernant les wake locks

L'utilisation d'un wakelock peut nuire aux performances de l'appareil. Si vous devez utiliser un verrouillage de réveil, il est important de le faire correctement. Ce document présente quelques bonnes pratiques qui peuvent vous aider à éviter les pièges courants liés aux wake locks.

Nommez correctement le wakelock

Nous vous recommandons d'inclure le nom du package, de la classe ou de la méthode dans la balise de wakelock. Ainsi, en cas d'erreur, il est plus facile de trouver l'emplacement dans votre code source où le verrouillage de réveil a été créé. Voici quelques conseils supplémentaires :

  • N'indiquez aucune information permettant d'identifier personnellement l'utilisateur dans le nom, comme une adresse e-mail. Si l'appareil détecte des informations permettant d'identifier personnellement l'utilisateur dans le tag de wakelock, il enregistre _UNKNOWN au lieu du tag que vous avez spécifié.
  • N'obtenez pas le nom de la classe ou de la méthode par programmation, par exemple en appelant getName(). Si vous essayez d'obtenir le nom par programmation, il peut être obscurci par des outils tels que Proguard. Utilisez plutôt une chaîne codée en dur.
  • N'ajoutez pas de compteur ni d'identifiants uniques pour réactiver les balises de wakelock. Le code qui crée un verrouillage de réveil doit utiliser le même tag chaque fois qu'il s'exécute. Cette pratique permet au système d'agréger l'utilisation du verrouillage de réveil de chaque méthode.

Assurez-vous que votre application est visible au premier plan.

Lorsqu'un verrouillage de réveil est actif, l'appareil consomme de l'énergie. L'utilisateur de l'appareil doit être informé de ce qui se passe. Pour cette raison, si vous utilisez un wakelock, vous devez afficher une notification à l'utilisateur. En pratique, cela signifie que vous devez obtenir et conserver le wakelock dans un service de premier plan. Les services de premier plan doivent afficher une notification.

Si un service de premier plan n'est pas le bon choix pour votre application, vous ne devriez probablement pas non plus utiliser de verrouillage de réveil. Consultez la documentation Choisir la bonne API pour maintenir l'appareil en éveil pour découvrir d'autres façons d'effectuer des tâches lorsque votre application n'est pas au premier plan.

Simplifiez la logique

Assurez-vous que la logique d'acquisition et de libération des wakelocks est aussi simple que possible. Lorsque votre logique de wakelock est liée à des machines d'état, à des délais d'exécution, à des pools d'exécuteurs ou à des événements de rappel complexes, tout bug subtil dans cette logique peut entraîner le blocage du wakelock plus longtemps que prévu. Ces bugs sont difficiles à diagnostiquer et à déboguer.

Vérifiez que le wakelock est toujours libéré.

Si vous utilisez un wakelock, vous devez vous assurer que chaque wakelock acquis est correctement libéré. Ce n'est pas toujours aussi simple qu'il y paraît. Par exemple, le code suivant pose problème :

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
}

Le problème ici est que la méthode doTheWork() peut générer l'exception MyException. Si c'est le cas, la méthode doSomethingAndRelease() propage l'exception vers l'extérieur, et elle n'atteint jamais l'appel release(). Le résultat est que le verrouillage de réveil est acquis, mais pas libéré, ce qui est très mauvais.

Dans le code corrigé, doSomethingAndRelease() s'assure de libérer le verrouillage de réveil même si une exception est générée :

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();
    }
}