Хабрахабр

Как оптимизировать энергопотребление в iOS

image

Когда это происходит? Пользователи устройств под управлением iOS часто жалуются, что аккумулятор быстро разряжается. Например, насыщенный обмен через разные виды приемопередатчиков (сотовая связь, bluetooth) или интенсивная отрисовка графики. Чаще всего при использовании GPS, но есть и другие причины ускоренного разряда батареи. Пользователям важно, чтобы заряда хватало надолго, поэтому при разработке стоит избегать решений, которые повышают энергопотребление. Некоторые любители яблочных девайсов грешат на батарею, но часто в быстрой разрядке виноваты разработчики приложений. Чем дольше iPhone включен, тем больше шанс, что пользователь откроет приложение и будет им пользоваться. Но зачем разработчикам вообще думать о том, как долго телефон держит заряд?

Я рассмотрю основные энергопотребители и подходы, которые помогают уменьшить энергопотребление девайса.

Основные энергопотребители

Больше всего заряд расходуют:

  • CPU (central processing unit, центральный процессор);
  • Взаимодействие с хранилищем
  • Приемопередатчики сигналов
  • Отрисовка графики

Как потребляется энергия при выполнении работы?

1. image
Рис. Энергопотребление при выполнении работы.

1 видно, как потребляется энергия, когда устройство выполняет работу. На рис. Также видим разделение на две части: фиксированное и динамическое энергопотребление.

Фиксированное энергопотребление — энергия, которая нужна, чтобы поддерживать работу системы, активировать передатчики данных (будь то сотовая связь, Wi-Fi, GPS) и т.д.

Динамическое энергопотребление — количество энергии, которое необходимо для выполнения полезной работы.

1 для большей ясности: Пройдемся по состояниям с рис.

  1. Система находится в состоянии простоя — минимальное потребление энергии. Даже в состоянии простоя девайс потребляет энергию, чтобы оставаться отзывчивым.
  2. Происходит некая активность, например, пришло PUSH-уведомление.
  3. Простой, энергопотребление уменьшилось после того, как PUSH-уведомления обработалось.
  4. Опять некая активность, например, пользователь нажал на уведомление, и запустилось приложение. Оно отобразило полную информацию по уведомлению, после чего пользователь закрыл приложение.
  5. Простой, энергопотребление опять снизилось. Отметим, что это состояние идентично состоянию 3, вся разница в том, что после состояния 3 опять произошла активность, которая увеличила энергопотребление.
  6. Энергопотребление продолжает уменьшаться, и система опять входит в состояние простоя.

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

Что делать чтобы энергопотребление снизилось?

1. Избегать выполнения работы в состояние inactive

Для этого достаточно подписаться на делегаты Если приложение не отображается в данный момент (например, перекрыто другим приложением), останавливайте таймеры, потоки, работу по сети, прекращайте перерисовку экрана.

  • applicationWillResignActive(_:)
  • applicationDidBecomeActive(_:)

Соответствующие нотификации есть у NSNotification. Они будут вызваны в моменты перехода приложения из foreground и возвращения в него.

2. Совершать работу в оптимальный момент времени

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

С его помощью можно создавать запросы, а обрабатывать результаты уже при следующем запуске приложения. Для планирования работы по сети есть: URLSessionConfiguration.background(withIdentifier). При создании задачи система сама выбирает наиболее благоприятный момент для выполнения. Также поддерживается автоматическое повторение запроса в случае неудачи.

Когда стоит задуматься об использовании background конфигурации:

  1. Автоматическое сохранение
  2. Обработка данных
  3. Подкачка контента
  4. Выполнение чего-либо с интервалом 10 минут и более

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

3. Выполнять работу эффективнее

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

  • User Interactive — самая приоритетная очередь. Еще ее называют main или ui, потому что на этой очереди выполняются задачи по отрисовке интерфейса.
  • User Initiated — следующая по приоритету. Используется для выполнения задач, завершения которых ожидает пользователь (загрузка контента, обработка изображений).
  • Utility — долгие задачи. Пользователь знает, что такие задачи выполняются, и может ждать их завершения.
  • Background — самый низкий приоритет. Тут разработчику стоит задуматься, а можно ли отсрочить выполнение задачи? Если да, то используем URLSessionConfiguration.background(withIdentifier).

2. image
Рис. Энергопотребление на разных очередях.

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

4. Совершать меньше работы

Для это следует улучшать производительность по четырем направлениям:

CPU 1.

В этом помогут XCode Instruments. Сначала надо определить код, активно использующий CPU. Обычно такой код работает с таймерами и вызовами, которые останавливают поток: NSTimer, GCD timers, performSelector(withObject, afterDelay), CFRunLoopTimer, pthread_cond_timedwait(), sleep(), dispatch_semaphore_wait().

3. Рассмотрим этот процесс на примере таймера.
image
Рис. Энергопотребление при работе таймера.

Чтобы улучшить производительность при использовании таймера, используйте setTolerance. Видим накладные расходы, которые не успевают снизиться из-за частых срабатываний таймера. 0) // в промежутке 60 секунд будет вызван обработчик Это позволит выполнять срабатывания в оптимальное время, выбранное системой.
myTimer.setTolerance(60.

Отрисовка графики
Чтобы сэкономить энергию, не совершайте лишних действий. 2. Избегайте наложения блюров на часто перерисовывающиеся объекты, такое наложение заставит блюр постоянно перерисовываться. Например, вместо вызова setNeedsDisplay, который перерисует все View, вызовите setNeedsDisplayInRect. Мониторить отрисовку можно через Quartz Debug или Instruments. Также избегайте лишних перерисовываний, выводящих энергопотребление из спящего уровня.

Взаимодействие с хранилищем 3.

  • Помните, что операции записи потребляют гораздо больше энергии, чем операции чтения
  • Группируйте операции записи, чтобы уменьшить фиксированное энергопотребление
  • Используйте кэширование

Приемопередатчики сигналов
Различные виды передатчиков (мобильная связь, Wi-Fi, Bluetooth, GPS) часто используются в приложениях. 4. Посмотрим на график энергопотребления при таком подходе. Обычно обращения к ним происходят, как только это инициировал пользователь или появились данные для отправки.

4. image
Рис. Энергопотребление при активном взаимодействии по сети с интервалом.

Стоит также учитывать, что расход энергии зависит от типа приемопередатчика, которым мы пользуемся. Из-за фиксированных расходов на активацию передатчика энергопотребление остается высоким все время, когда периодически происходит отправка данных. Например, на 5S при использовании Wi-Fi батарея выдерживает 10 часов серфинга, а с мобильной связью — 8 часов.
Если есть возможность, буферизуйте данные и отправляйте их все в один момент времени, как на графике ниже.

5. image
Рис. Энергопотребление при активном сетевом взаимодействии в один промежуток времени.

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

Практики сокращения энергопотребления в background

Активности для этого раздела можно разделить на четыре группы: Рассмотрим практики в моменты, когда приложение находится в background.

Notifications

Локальные уведомления не требуют взаимодействия по сети и не запускают приложение. Notifications делятся на Local (запланированы приложением) и Push (отправляются с сервера). Используйте local notifications всегда, когда это возможно. При уведомлении через APNS, устройство проснется, и приложение будет запущено в background для обработки уведомления (если необходимо подкачать данные для отображения уведомления).
Как здесь снизить энергопотребление? Также выставляйте приоритет для APNS уведомления и, в зависимости от него, доставка произойдет немедленно, либо оптимальное время будет выбрано системой.

VoIP

Надо было вручную возобновлять сессию, опрашивать сервер, из-за этого энергия расходовалась быстро. Раньше поддерживать VoIP можно было только до тех пор, пока приложение не перешло в состояние terminated. Т.е. Сейчас повышенного потребления можно избежать: появились PUSH-уведомления для звонков. И больше нет необходимости поддерживать постоянное соединение с сервером. когда приходит такое уведомление, приложение просыпается и начинает обрабатывать звонок. Используйте новое API для снижения энергопотребления.

Location

При использовании GPS, оптимизация энергопотребления приводит к снижению точности определения геопозиции. Процесс определения геолокации вызывает сильное энергопотребление, из-за того, что нужно держать GPS приемник активным длительное время для позиционирования девайса. В приложениях типа игр Pokemon Go снижение точности определения геопозиции неприемлемо, но во многих других ситуациях это допустимо.

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

  • Переключать режимы точности. Например, разрабатывается квест по городу на основе геолокации. Необходимо, чтобы пользователь с точностью до 10 метров достиг определенного места на карте. В этом случае стоит использовать significantLocationChange, а затем переходить к более точным настройкам. SignificantLocationChange — наиболее энергоэффективный метод определения геолокации, предоставляющий данные с точностью ~700 метров. Пока пользователь не достиг даже 700 — метрового радиуса от цели, зачем тратить батарею на получение более точных данных?
  • Откладывать обработку сигналов от LocationManager до тех пор, пока приложение находится в background. Например, мы делаем фитнес приложение, которое собирает данные во время бега. Пока телефон лежит в кармане, и им все равно никто не пользуется, не стоит разряжать, обрабатывая сигналы об изменении геопозиции. Пусть лучше они буферизуются в системе, а когда пользователь решит просмотреть свою дистанцию и откроет приложение, они поступят на обработку. В создании такого приложения вам поможет метод deferredLocationUpdatesAvailable и allowDeferredLocationUpdatesUntilTraveled.
  • Обнаруживать регионы. startMonitoringForRegion позволит обнаруживать заранее установленные регионы, тем самым избавив от необходимости постоянно получать текущую позицию и проверять находится ли пользователь в нужном месте.

Коротко — используйте наихудшую точность определения геопозиции, которая позволяет решить вашу бизнес — задачу.

Bluetooth

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

Есть еще одна возможность экономии — не “будить” приложение по событиям от bluetooth приемника.

Мы оптимизировали его работу таким образом, чтобы сигналы от LocationManager обрабатывались только, когда пользователь открыл приложение. Например, вспомним фитнес приложение. Это позволит не поддерживать связь с фитнес-трекером все время, забирая информацию о пульсе, ведь ее все равно никто не посмотрит во время бега. В этот самый момент стоит обратиться по bluetooth к фитнес-трекеру и забрать данные о пульсе.

Резюме

Используйте приемы для снижения энергопотребления: Энергопотребление быстро увеличивается, но долго снижается после выполнения работы.

  • Помните, что фиксированное энергопотребление можно уменьшить, группируя выполнение задач.
  • Старайтесь отдавать системе подгрузку или загрузку большого объема данных. Она это сделает в оптимальный момент.
  • Не выводите приложение из состояния простоя, когда этого можно избежать
Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть