Освой программирование играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

Doze

Новые алгоритмы сна под названием Doze помогут вашему устройству работать на одной зарядке дольше: в моменты, когда аппарат долго лежит неподвижно, не подключен к зарядке и его дисплей не включается для отображения уведомлений, все приложения ставятся на паузу (App Standby), передача данных минимизируется, процессор переходит в энергосберегающий режим, все синхронизации и прочие любители что-нибудь сделать, пока телефон «бездельничает» отправляются в сон.

Впервые этот режим был внедрён в Android Marshmallow и в следующих версиях требования ужесточаются всё больше и больше.

В спящем режиме не выполняются сетевые запросы, кроме GCM с высоким приоритетом. Также могут блокироваться операции синхронизации, задачи по сигнализации событий, сканирование сетей Wi-Fi, работа GPS.

Для особо важных задач можно запустить метод setAndAllowWhileIdle() от AlarmManager, но не чаше одного раза в 15 минут.

Doze Mode

Когда устройство на Android Marshmallow лежит без движения и без зарядки, спустя час оно переходит в Doze Mode. Режим отключки, когда почти все приложения перестают жрать батарею. Это происходит не сразу, а по шагам:

  • ACTIVE — Устройство используется или на зарядке
  • INACTIVE — Устройство недавно вышло из активного режима (пользователь выключил экран, выдернул зарядку и т.п.)
  • ...30 минут
  • IDLE_PENDING — Устройство готовится перейти в режим ожидания
  • ...30 минут
  • IDLE — Устройство в режиме бездействия
  • IDLE_MAINTENANCE — Открыто короткое окно, чтобы приложения выполнили свою работу

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

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


adb shell dumpsys battery unplug

Далее вы можете увидеть состояние устройства.


adb shell dumpsys deviceidle step

Команда будет возвращать следующие строки в разное время.


Stepped to: ACTIVE
Stepped to: IDLE_PENDING
Stepped to: SENSING
Stepped to: IDLE
Stepped to: IDLE_MAINTENANCE

Вернуть батарею обратно в обычное состояние зарядки от сети.


adb shell dumpsys battery reset

Увидеть все доступные команды.


adb shell dumpsys deviceidle -h

В момент, когда устройство переходит в состояние IDLE:

  • Доступ приложению к сети отключен, пока приложение не получит high-priority GCM-push
  • Система игнорирует Wake Lock. Приложения могут сколько угодно пытаться запросить пробуждение процессора — они их не получат
  • Запланированные Alarm в AlarmManager не будут вызываться, кроме тех, которые будут обновлены с помощью setAndAllowWhileIdle()
  • Система не производит поиска сетей Wi-Fi
  • NetworkPolicyManagerService: пропускает только приложения из белого списка
  • JobSchedulerService: все текущие задачи отменяются. Новые откладываются до пробуждения
  • SyncManager: все текущие отменяются, новые откладываются до пробуждения
  • PowerManagerService: только задачи приложений из белого списка

Соответственно, если наше приложение является чатом, то мы можем отправить с сервера push с полем priority = high. А если у нас приложение будильник, то мы должны обязательно вызвать setAndAllowWhileIdle() или setExactAndAllowWhileIdle().

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

Режим Standby

Если у приложения есть фоновые задачи, но приложение простаивает, то включается режим Standby.

Если приложение простаивает долгое время, то система разрешит делать ему запрос в сеть один раз в сутки.

Ремжим App Standby отправляет в изоляцию приложения, которые не подходят под условия:

  • Пользователь явно запустил приложение
  • Приложение имеет процесс, работающий в данный момент на переднем плане (Activity или foreground service, или используется другая активность или foreground service)
  • Приложение создало уведомление, которое висит в списке уведомлений
  • Пользователь принудительно добавил приложение в список исключений оптимизации в настройках системы

Этот режим тоже можно тестировать с помощью команд.


adb shell am broadcast -a android.os.action.DISCHARGING
shell am set-inactive <App_Package_Name> true

Разбудить приложение можно командой.


adb shell am set-inactive <App_Package_Name> false

Проверить статус приложения:


adb shell am get-inactive <App_Package_Name>

Например, может вернуться строка.


Idle=false

Есть специальный белый список Whitelist, в который пользователь может добавить исключения. Приложениям из белого списка не страшны ни Doze Mode ни App Standby.

Пользователь может настроить нужные приложения, чтобы они не включали режим ожидания Standby. Для этого идём в Настройки | Приложения, нажимаем на значок шестерёнки и выбираем пункт Экономия заряда батареи. В выпадающем списке Не экономят заряд можно увидеть программы, которые не используют режим ожидания. Переключитесь на Все приложения и выберите нужно приложение из списка. В диалоговом окне можете установить режим Не экономить.

Можно программно узнать, находится ли приложение в "белом списке" приложений, которым разрешено не экономить заряд. Нужно указать имя пакета приложения (не обязательно указывать своё приложение).


// API 23 и выше
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
boolean inWhiteList = powerManager.isIgnoringBatteryOptimizations("ru.alexanderklimov.cats");
System.out.println(inWhiteList);

Если находится, то вернёт true, иначе - false.

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


startActivity(new
        Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS));

Более агрессивный способ, когда вы явно вызывает диалоговое окно для добавления приложения в белый список.


Intent intent = new
        Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
        Uri.parse("package:" + getPackageName()));
startActivity(intent);

В манифесте следует прописать разрешение.


<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>

Не экономить

Если приложение уже находится в белом списке, то диалоговое окно не появится.

Реклама