web-dev-qa-db-fra.com

Réveil excessif du gestionnaire d'alarmes dans Android avec localisation des services Google Play

J'ai reçu un rapport de performance de Android Vital sur la console Google Play à propos des réveils excessifs du gestionnaire d'alarmes:

https://developer.Android.com/topic/performance/vitals/wakeup.html

J'utilise l'API de localisation des services Google Play pour demander des mises à jour de localisation en arrière-plan. Sur le rapport, il montre que les réveils excessifs de réveil ont été causés par com.google.Android.location.ALARM_WAKEUP_LOCATOR de LocationListener.

Sous l'extrait de code qui provoque les alarmes:

private synchronized void buildGoogleApiClient() {
    mGoogleApiClient = new GoogleApiClient.Builder(context)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();
    mGoogleApiClient.connect();
}

/**
 * Runs when a GoogleApiClient object successfully connects.
 */
@Override
public void onConnected(Bundle connectionHint) {
    try {
        // Set location request
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(5 * 60000);
        mLocationRequest.setFastestInterval(60000);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
        mLocationRequest.setMaxWaitTime(30 * 60000);

        // Create a pending intent to listening on location service when the update become available
        Intent mIntent = new Intent(context, LocationReceiver.class);
        mIntent.setAction(LocationReceiver.LOCATION_EXTRA);
        mPendingIntent = PendingIntent.getBroadcast(context, 42, mIntent, PendingIntent.FLAG_CANCEL_CURRENT);
        // Permission check before launching location services
        if (ContextCompat.checkSelfPermission(context,
                Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, mPendingIntent);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Cette réveil d'alarme est-elle liée à l'API de localisation des services Google Play?

Quelqu'un sait-il comment résoudre ce problème?

26
poiuytrez

API de localisation Google

Il s'agit d'un problème avec com.google.Android.location.ALARM_WAKEUP_LOCATOR réveiller les appareils toutes les 60 secondes et les garder éveillés pendant 15 secondes au maximum, ce qui provoque des problèmes majeurs de drainage de la batterie.

Il y a eu correctifs pour les utilisations du téléphone via --- apps externes et pour enseigner aux utilisateurs comment révoquer l'autorisation pour une application.

La solution

Ce qui suit fournit les outils pour réduire l'utilisation de la batterie de l'application.

Il est impossible de fournir une solution personnalisée pour l'application, car la solution dépend du cas d'utilisation et de la logique métier de l'application et d'une analyse coûts-avantages de ce que vous souhaitez réaliser avec les mises à jour de localisation.

Intervalles de temps

Il n'est pas surprenant qu'il y ait des problèmes de performances de la batterie. À partir des paramètres suivants:

mLocationRequest.setInterval(5 * 60000);
mLocationRequest.setFastestInterval(60000);
mLocationRequest.setMaxWaitTime(30 * 60000);

Votre intervalle est configuré pour se mettre à jour toutes les 5 minutes (5 * 60000 ms). C'est 24 heures par jour. Si cela se met à jour toutes les 5 minutes: 12 fois/heure == 288 fois par jour.

L'intervalle le plus rapide étant fixé à 1 minute (60000). Bien que cela soit disponible car l'emplacement est accessible ailleurs sur l'appareil, il utilisera toujours de l'énergie dans votre application).

Le temps d'attente maximal n'est que de 30 minutes. Ce qui signifie au mieux que l'appareil sera réveillé et interrogé au moins 48 fois par jour.

Augmentez ces temps .

setMaxWaitTime ... Cela peut consommer moins de batterie et donner des emplacements plus précis, selon les capacités matérielles de l'appareil. Vous devez définir cette valeur pour qu'elle soit aussi grande que possible pour vos besoins si vous n'avez pas besoin d'une livraison immédiate sur site. ...

Dans Android 8 Google a limité le nombre de demandes à seulement quelques par heure . Pensez à utiliser ceci comme guide pour définir les intervalles des demandes.

Limiter le nombre de mises à jour

Le nombre de mises à jour dans un certain délai peut être limité. En annulant activement la demande de localisation une fois que le nombre de mises à jour a été utilisé ou en définissant un expiration sur la demande. De cette façon, l'application peut être gérée en créant une demande sur un déclencheur dans l'application et gérée avec soin afin qu'elle ne continue pas sans fin. Il est difficile de créer un flux, car je ne connais pas le cas d'utilisation de l'application.

setNumUpdates (int numUpdates)

Par défaut, les emplacements sont mis à jour en continu jusqu'à ce que la demande soit explicitement supprimée, mais vous pouvez éventuellement demander un nombre défini de mises à jour. Par exemple, si votre application n'a besoin que d'un seul nouvel emplacement, appelez cette méthode avec une valeur de 1 avant de transmettre la demande au client d'emplacement.

Arrêter les mises à jour de position

Une autre option consiste à gérer arrêter les mises à jour des emplacements lorsqu'ils ne sont pas nécessaires. Les liens donnent des exemples d'appels quand une activité perd le focus, mais cela peut être implémenté dans l'application, lorsque certaines exigences sont remplies (c'est dans votre logique métier) ou même en donnant à l'utilisateur de l'activer et de le désactiver depuis l'application lui-même.

Optimisation de la batterie

Assurez-vous que votre application n'est pas en ignorant les optimisations de batterie .

Déplacement

Gérer également setSmallestDisplacement (float smallestDisplacementMeters) aidera à affiner l'application, en fonction de la logique métier.

ce qui suit a été écrit avant la question mise à jour.

La fréquence à laquelle les mises à jour de l'application peuvent être définies par le développeur et l'utilisateur. Les intervalles et priorités .

Pour le développeur .

Vous pouvez les définir lors d'une demande de localisation par exemple:

protected void createLocationRequest() {
    LocationRequest mLocationRequest = new LocationRequest();
    mLocationRequest.setInterval(10000);
    mLocationRequest.setFastestInterval(5000);
    mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
}

Il existe également un paramètre pour PRIORITY_NO_POWER , ce qui signifie que l'application ne recevra les mises à jour que lorsque l'utilisateur les demandera.

Pour l'utilisateur.

Vous devrez inviter l'utilisateur à modifier les paramètres de localisation

task.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
    @Override
    public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
        // All location settings are satisfied. The client can initialize
        // location requests here.
        // ...
    }
});

task.addOnFailureListener(this, new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception e) {
        int statusCode = ((ApiException) e).getStatusCode();
        switch (statusCode) {
            case CommonStatusCodes.RESOLUTION_REQUIRED:
                // Location settings are not satisfied, but this can be fixed
                // by showing the user a dialog.
                try {
                    // Show the dialog by calling startResolutionForResult(),
                    // and check the result in onActivityResult().
                    ResolvableApiException resolvable = (ResolvableApiException) e;
                    resolvable.startResolutionForResult(MainActivity.this,
                            REQUEST_CHECK_SETTINGS);
                } catch (IntentSender.SendIntentException sendEx) {
                    // Ignore the error.
                }
                break;
            case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                // Location settings are not satisfied. However, we have no way
                // to fix the settings so we won't show the dialog.
                break;
        }
    }
});

Pour gérer les modifications dans les paramètres utilisateur, utilisez un rappel de localisation.

... vous pouvez utiliser la nouvelle classe LocationCallback à la place de votre LocationListener actuelle pour recevoir LocationAvailable mises à jour en plus des mises à jour de localisation, vous donnant ainsi rappel simple chaque fois que les paramètres peuvent avoir changé, ce qui affectera l'ensemble actuel de LocationRequests.

Google a résol ce problème dans Android 8.

Afin de réduire la consommation d'énergie, Android 8.0 (API niveau 26) limite la fréquence à laquelle les applications d'arrière-plan peuvent récupérer la position actuelle de l'utilisateur. Les applications peuvent recevoir des mises à jour de position seulement quelques fois par heure.

Remarque: Ces limitations s'appliquent à toutes les applications utilisées sur les appareils exécutant Android 8.0 (API niveau 26) ou supérieur, quelle que soit la version du SDK cible d'une application.


Si vous utilisez le gestionnaire d'alarmes.

Cela peut être lié à Alarm Manager .

Ce n'est pas une solution simple, vous devrez finalement réécrire la façon dont vous planifiez vos mises à jour.

  1. Pour au moins ralentir le problème, vous devrez déboguer votre code et rechercher toutes les instances dans lesquelles Alarm Manager appelle ou crée des planifications et réduit les intervalles.

  2. Après cela, vous devrez réécrire toute la partie de la planification de la mise à jour de l'emplacement de l'application.

Résoudre le problème

Identifiez les endroits de votre application où vous planifiez des alarmes de réveil et réduisez la fréquence de déclenchement de ces alarmes. Voici quelques conseils:

  • Recherchez les appels aux différentes méthodes set () dans AlarmManager qui incluent soit RTC_WAKEUP ou ELAPSED_REALTIME_WAKEUP.
  • Nous vous recommandons d'inclure le nom de votre package, classe ou méthode dans le nom de la balise de votre alarme afin que vous puissiez facilement identifier l'emplacement dans votre source où l'alarme a été définie. Voici quelques conseils supplémentaires:
    • Oubliez toute information d'identification personnelle (PII) dans le nom, comme une adresse e-mail. Sinon, le périphérique enregistre _UNknown au lieu du nom de l'alarme.
    • N'obtenez pas le nom de la classe ou de la méthode par programme, par exemple en appelant getName () , car cela pourrait être obscurci par Proguard. Utilisez plutôt une chaîne codée en dur.
    • N'ajoutez pas de compteur ou d'identifiants uniques aux étiquettes d'alarme. Le système ne pourra pas agréger les alarmes définies de cette façon car elles ont toutes des identifiants uniques.

Après avoir résolu le problème, vérifiez que vos alarmes de réveil fonctionnent comme prévu en exécutant la commande ADB suivante:

adb Shell dumpsys alarm

Cette commande fournit des informations sur l'état du service du système d'alarme sur l'appareil. Pour plus d'informations, voir dumpsys .

Si vous avez des problèmes particuliers avec l'un des éléments ci-dessus, vous devrez publier une autre question avec un mcve .

Pour améliorer l'application, cela impliquerait de réécrire le code comme mentionné ici dans Meilleures pratiques . N'utilisez pas le gestionnaire d'alarmes pour planifier des tâches en arrière-plan, et l'emplacement serait considéré comme une tâche en arrière-plan, si le téléphone est en veille. De plus, vous dites que c'est une tâche d'arrière-plan. Utilisez JobScheduler ou Firebase JobDispatcher .

Si le gestionnaire d'alarmes est le meilleur choix ( qui n'est pas ici) il est important d'avoir une bonne lecture ici Planification des alarmes répétitives , mais vous devez Comprendre les compromis

Une alarme mal conçue peut entraîner une décharge de la batterie et une charge importante sur les serveurs.

30
Yvette Colomb