Минимизации влияния регулярных обновлений

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

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

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

Используйте Google Cloud Messaging в качестве альтернативы опроса

Каждый раз, когда ваше приложение опрашивает ваш сервер, чтобы проверить требуется ли обновление, вы активируете функции беспроводной сети, потребляя энергию без необходимости, до 20 секунд для типичной 3G сети.

Google Cloud Messaging для Android (GCM) это легкий механизм, используемый для передачи данных с сервера конкретному экземпляру приложения. Используя GCM, ваш сервер может уведомить ваше приложение, работающее на конкретном устройстве, о том что есть новые данные доступные для него.

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

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

GCM реализован с использованием постоянного TCP/IP соединения. Конечно можно реализовать собственную службу посылки сообщений, но рекомендуется использовать GCM. Это сводит к минимуму количество постоянных соединений и позволяет платформе оптимизировать сетевой трафик и свести к минимуму связанное с этим влияние на время автономной работы батареи.

Оптимизация опросов с помощью событий с неточным интервалом и экспоненциальной выдержкой

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

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

При планировании обновлений, используйте события с неточными интервалами, которые позволяют системе делать "фазовый сдвиг" того момента, когда необходимо запустить событие.

int alarmType = AlarmManager.ELAPSED_REALTIME;
long interval = AlarmManager.INTERVAL_HOUR;
long start = System.currentTimeMillis() + interval;

alarmManager.setInexactRepeating(alarmType, start, interval, pi);

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

Везде, где возможно, установите тип сигнала в ELAPSED_REALTIME или RTC вместо того, чтобы их _WAKEUP эквиваленты. Генерация событий после того как телефон перейдет из состояния ожидания в активное состояние еще больше снижает влияние на работу батареи.

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

Один из подходов заключается в реализации шаблона экспоненциальной выдержки для уменьшения частоты ваших обновлений (и/или степени предварительной выборки), если приложение не используется долгое время с момента предыдущего обновления. Часто бывает полезно изменить минимальную частоту обновления, и сбросить значение частоты, когда приложение снова используется, например:

SharedPreferences sp = 
  context.getSharedPreferences(PREFS, Context.MODE_WORLD_READABLE);

boolean appUsed = sp.getBoolean(PREFS_APPUSED, false);
long updateInterval = sp.getLong(PREFS_INTERVAL, DEFAULT_REFRESH_INTERVAL);

if (!appUsed)
  if ((updateInterval *= 2) > MAX_REFRESH_INTERVAL)  
    updateInterval = MAX_REFRESH_INTERVAL;

Editor spEdit = sp.edit();
spEdit.putBoolean(PREFS_APPUSED, false);
spEdit.putLong(PREFS_INTERVAL, updateInterval);
spEdit.apply();

rescheduleUpdates(updateInterval);
executeUpdateOrPrefetch();

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

Стоимость инициирования подключения к сети не зависит от того, можете ли вы обратиться к серверу и скачать данные или нет. Для срочной передачи данных, где успешное завершение важно, экспоненциальный алгоритм может быть использован для снижения частоты повторных попыток, чтобы свести к минимуму связанное с этим влияние на батарею, например:

private void retryIn(long interval) {
  boolean success = attemptTransfer();
    
  if (!success) {
    retryIn(interval*2 < MAX_RETRY_INTERVAL ? 
            interval*2 : MAX_RETRY_INTERVAL);      
  }
}

Кроме того, для терпимых к неудаче передачам данных (как например, регулярные обновления), вы можете просто игнорировать неудачные попытки подключения и неудачные пересылки данных.