Чрезмерные пробуждения Alarm Manager в Android с помощью Google Play Services Location

Я получил отчет о производительности от Android Vital на консоли Google Play о пробуждениях из-за чрезмерной тревоги:

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

Я использую Location API из Google Play Services, чтобы запрашивать обновления местоположения в фоновом режиме. В отчете показано, что чрезмерные пробуждения были вызваны com.google.android.location.ALARM_WAKEUP_LOCATOR из LocationListener.

Ниже фрагмента кода, который вызывает тревоги:

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

Связан ли этот сигнал тревоги с Location API из сервисов Google Play?

Кто-нибудь знает, как решить эту проблему?

1 ответ

Решение

API местоположения Google

Эта проблема связана с тем, что com.google.android.location.ALARM_WAKEUP_LOCATOR активирует устройства каждые 60 секунд и не дает им проснуться в течение 15 секунд, что приводит к серьезным проблемам с разрядкой аккумулятора.

Были исправления для использования телефона через внешние приложения и обучение пользователей тому, как на самом деле отозвать разрешение для приложения.

Решение

Ниже приведены инструменты для снижения расхода батареи приложения.

Невозможно предоставить индивидуальное решение для приложения, так как решение зависит от варианта использования и бизнес-логики приложения, а также анализа затрат и выгод от того, что вы хотите достичь с помощью обновлений местоположения.

Интервалы времени

Не удивительно, что есть проблемы с производительностью батареи. Из следующих настроек:

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

Ваш интервал обновляется каждые 5 минут (5 * 60000 мс). Это 24 часа в сутки. Если это успешно обновляется каждые 5 минут: 12 раз / час == 288 раз в день.

Самый быстрый интервал устанавливается в 1 минуту (60000). Несмотря на то, что это доступно, потому что к местоположению обращаются в другом месте на устройстве, оно все равно будет использовать питание в вашем приложении).

Максимальное время ожидания составляет всего 30 минут. Это означает, что в лучшем случае устройство будет просыпаться и опрашиваться как минимум 48 раз в день.

Увеличьте эти времена.

setMaxWaitTime... Это может потреблять меньше батареи и давать более точные местоположения, в зависимости от аппаратных возможностей устройства. Вы должны установить это значение как можно большим для ваших нужд, если вам не нужна немедленная доставка в другое место....

В Android 8 Google ограничил количество запросов только несколькими в час. Подумайте об этом, чтобы установить интервалы для запросов.

Ограничение количества обновлений

Количество обновлений в течение определенного периода времени может быть ограничено. Либо активно отменяя запрос местоположения после использования количества обновлений, либо устанавливая срок действия запроса. Таким образом, приложением можно управлять, создавая запрос на некоторый триггер в приложении и тщательно управляя им, чтобы он не продолжался бесконечно. Трудно создать поток, так как я не знаю сценарий использования приложения.

setNumUpdates (int numUpdates)

По умолчанию местоположения постоянно обновляются до тех пор, пока запрос не будет явно удален, однако вы можете дополнительно запросить установленное количество обновлений. Например, если вашему приложению требуется только одно новое местоположение, вызовите этот метод со значением 1, прежде чем передать запрос клиенту местоположения.

Остановить обновления местоположения

Другой вариант - управлять обновлениями мест остановки, когда они не нужны. В ссылках приводятся примеры вызова этого, когда действие теряет фокус, однако это может быть реализовано в приложении, когда выполняются определенные требования (это в вашей бизнес-логике) или даже если пользователь дает возможность включать и выключать его из приложения. сам.

Оптимизация батареи

Убедитесь, что ваше приложение не игнорирует оптимизацию батареи.

водоизмещение

Также управление setSmallestDisplacement (float smalllestDisplacementMeters) поможет настроить приложение в зависимости от бизнес-логики.

следующее было написано перед обновленным вопросом.

Как часто обновления приложения могут быть установлены как разработчиком, так и пользователем. Интервалы и приоритеты.

Для разработчика.

Вы можете установить их при создании запроса местоположения, например:

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

Существует также настройка для PRIORITY_NO_POWER, которая означает, что приложение будет получать обновления только тогда, когда пользователь их запрашивает.

Для пользователя.

Вам нужно будет предложить пользователю изменить настройки местоположения.

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

Для управления изменениями в настройках пользователя используйте обратный вызов местоположения.

... вы можете использовать новый класс LocationCallback вместо существующего LocationListener, чтобы получать обновления LocationAvailability в дополнение к обновлениям местоположения, предоставляя вам простой обратный вызов всякий раз, когда настройки могут измениться, что повлияет на текущий набор LocationRequests.

Google решил эту проблему в Android 8.

В целях снижения энергопотребления Android 8.0 (уровень API 26) ограничивает частоту, с которой фоновые приложения могут извлекать текущее местоположение пользователя. Приложения могут получать обновления местоположения только несколько раз в час.

Примечание. Эти ограничения применяются ко всем приложениям, используемым на устройствах под управлением Android 8.0 (уровень API 26) или выше, независимо от целевой версии SDK приложения.


При использовании диспетчера тревог.

Это может быть связано с диспетчером аварий.

Это не простое исправление, в конечном итоге вам нужно переписать, как вы планируете свои обновления.

  1. Чтобы хотя бы замедлить проблему, вам нужно отладить свой код и найти все случаи, когда Alarm Manager вызывает или создает расписания и сокращает интервалы.

  2. После этого вам нужно будет переписать всю часть планирования обновлений местоположения приложения.

Решить проблему

Определите места в вашем приложении, где вы планируете будильники и уменьшите частоту их срабатывания. Вот несколько советов:

  • Ищите вызовы различных методов set() в Alarm Manager, которые включают флаг RTC_WAKEUP или ELAPSED_REALTIME_WAKEUP.
  • Мы рекомендуем включить название вашего пакета, класса или метода в имя тега вашего будильника, чтобы вы могли легко определить местоположение в вашем источнике, где был установлен будильник. Вот несколько дополнительных советов:
    • Оставьте любую личную информацию (PII) в имени, такую ​​как адрес электронной почты. В противном случае устройство регистрирует _UNKNOWN вместо имени тревоги.
    • Не получайте имя класса или метода программно, например, вызывая getName (), потому что оно может быть запутано Proguard. Вместо этого используйте жестко закодированную строку.
    • Не добавляйте счетчик или уникальные идентификаторы в теги тревоги. Система не сможет агрегировать сигналы тревоги, которые установлены таким образом, потому что все они имеют уникальные идентификаторы.

После исправления проблемы убедитесь, что ваши аварийные сигналы работают должным образом, выполнив следующую команду ADB:

Оболочка АДБ

Эта команда предоставляет информацию о состоянии службы охранной системы на устройстве. Для получения дополнительной информации см. Dumpsys.

Если у вас есть конкретные проблемы с любым из вышеперечисленного, вам нужно опубликовать еще один вопрос в mcve.

Чтобы улучшить приложение, оно должно было бы переписать код, как упомянуто здесь в Best Practices. Не используйте диспетчер тревог для планирования фоновых задач, и местоположение будет считаться фоновой задачей, если телефон спит. Плюс вы говорите, что это фоновая задача. Используйте JobScheduler или Firebase JobDispatcher.

Если Alarm Manager - лучший выбор (которого здесь нет), важно прочитать его здесь. Планирование повторяющихся сигналов, но вам нужно понять компромиссы

Плохо спроектированная сигнализация может привести к разрядке аккумулятора и значительной нагрузке на серверы.

Другие вопросы по тегам