- Полный список
- IntentService
- Foreground
- Автозагрузка
- Android Foreground Service Example
- 1. Android Foreground Service Example.
- 2. Example Source Code.
- 2.1 Android Foreground Service Class.
- 2.2 Main Activity.
- 2.3 Layout XML File.
- 2.4 Android Manifest Xml File.
- 2.5 Assign FOREGROUND_SERVICE Permission.
- Работа с фоновыми задачами в Android 12: переезжаем с foreground service на expedited jobs
- WorkManager и foreground service
- Expedited jobs
- Миграция foreground service на expedited job
- Вместо заключения
Полный список
— изучаем IntentService
— включаем режим Foreground для сервиса
— помещаем сервис в автозагрузку
Строили мы, строили, и, наконец, построили. Урок номер 100, с чем всех нас и поздравляю )
В этом уроке рассмотрим еще несколько полезных вещей про сервисы. Выносить каждую из них в отдельный урок я не стал, вполне можно в одном все рассмотреть. Проекты здесь тоже создавать не будем, чтобы урок не получился слишком громоздким. Я просто приведу некоторые куски кода и скрины для наглядности своих рассуждений. А если у вас будет желание, вы по этим наработкам сами можете создать проекты-примеры.
IntentService
Это подкласс обычного Service. Он используется, если вам в сервисе надо выполнять какие-то тяжелые задачи, и вы не хотите сами возиться с асинхронностью. Принцип работы этого вида сервиса прост. Он создает новый поток для своей работы. Затем берет все Intent пришедшие ему в onStartCommand и отправляет их на обработку в этот поток. Как именно обрабатываются Intent – зависит от нас, т.к. мы сами кодим это в методе onHandleIntent.
Т.е. приложение сыпет в сервис вызовами startService, в которых передает Intent-ы. IntentService принимает эти вызовы в onStartCommand, берет Intent-ы и отправляет их в очередь на обработку. И далее они поочередно обрабатываются в отдельном потоке методом onHandleIntent. Когда последний Intent из очереди обработан, сервис сам завершает свою работу.
В приложении делаем три вызова:
Где time – это время паузы, которую будем делать в сервисе, а label – просто метка, чтобы отличать вызовы.
Здесь необходим конструктор, в котором вызываем конструктор супер-класса и указываем какое-нить имя. Оно будет использовано для наименования потока.
В методе onHandleIntent кодим обработку Intent-ов. Достаем из них time и label, запускаем паузу на time секунд и выводим в лог label в начале и в конце.
В итоге, при запуске в логах видим:
11:07:37.880: D/myLogs(4137): onCreate
11:07:37.880: D/myLogs(4137): onHandleIntent start Call 1
11:07:40.880: D/myLogs(4137): onHandleIntent end Call 1
11:07:40.880: D/myLogs(4137): onHandleIntent start Call 2
11:07:41.880: D/myLogs(4137): onHandleIntent end Call 2
11:07:41.880: D/myLogs(4137): onHandleIntent start Call 3
11:07:45.890: D/myLogs(4137): onHandleIntent end Call 3
11:07:45.890: D/myLogs(4137): onDestroy
Сервис создался, вызовы выполнились по очереди и сервис завершил работу. От нас понадобилось только накодить обработку.
Foreground
Вы можете сказать системе, что ваш сервис очень важен для пользователя и его нельзя грохать при нехватке памяти. Это актуально, например, для музыкального плеера. В статус-бар при этом будет помещено уведомление.
На вход он принимает те же параметры, что и NotificationManager.notify – ID и Notification.
Т.е. вы создаете уведомление, назначаете ему ID и передаете это в startForeground. Сервис переходит в режим IDDQD :), а в статус-баре появилось уведомление.
Оно появилось в разделе для постоянных уведомлений (Ongoing).
Метод stopForeground (boolean removeNotification) — возвращает сервису способность быть убитым системой в случае острой нехватки памяти. А на вход он принимает boolean-значение – удалять уведомление из статус-бара или нет.
Уведомление также пропадет, когда сервис будет остановлен.
Эти методы работают, начиная с Android 2.0. Пример реализации для более ранних версий есть в хелпе.
Напомню, что уведомления мы научились создавать на прошлом уроке.
Автозагрузка
Сервисы для получения погоды или почты имеет смысл помещать в автозагрузку. Для этого нам надо создать BroadcastReceiver, настроить его IntentFilter на Action = android.intent.action.BOOT_COMPLETED, и добавить права android.permission.RECEIVE_BOOT_COMPLETED. Этот BroadcastReceiver будет вызван системой при старте системы и в нем мы кодим запуск сервиса.
Допустим, есть проект с сервисом MyService.
Создаем в проекте класс MyBroadReceiv
В манифесте добавляем его как Receiver и настраиваем фильтр
Добавляем права на получение сообщения о загрузке
Инсталлим проект на AVD. Закрываем AVD. Запускаем через меню в Eclipse: Window > AVD Manager. Находим там наш эмулятор и запускаем вручную.
Когда он запустился, смотрим логи
onReceive android.intent.action.BOOT_COMPLETED
MyService onCreate
MyService onStartCommand
Сработал BroadcastReceiver и запустил сервис.
Если после запуска AVD логи не отображаются, то откройте DDMS и во вкладке Devices явно выберите ваш AVD.
P.S. Я уже писал об этом, но напишу еще раз. Последующие уроки будут выходить по более свободному графику. Следите за обновлениями.
На следующем уроке:
— создаем свой ContentProvider
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
Источник
Android Foreground Service Example
Android foreground service is an android service object. It always runs in the foreground, this can avoid service objects being recycled by the android system when android os does not have enough resources. Android foreground service can interact with users through notification. It is usually used in a music player, file downloader, etc which user has few interactions with the player service but the service should not be stopped and recycled.
1. Android Foreground Service Example.
- There are 2 buttons in the Android app. When you click the START FOREGROUND SERVICE button, it will create and start a foreground service.
- The foreground service will show a head-up notification which will pop up at the screen top with max priority. The notification is also a text-style notification.
- There are two buttons in the notification, clicking each button will display a toast message at the screen bottom. When you click the STOP FOREGROUND SERVICE button, it will stop the service and remove the notification.
2. Example Source Code.
- The below source files are the example project files.
- There are two java files in this example MyForeGroundService.java & CreateForegroundServiceActivity.java.
- MyForeGroundService.java: This is the android foreground service class. It overrides the android.app.Service.onStartCommand(Intent intent, int flags, int startId) method. This method will be invoked when the activity invokes the startService(intent) method.
- In the onStartCommand method, it will check which button has been pressed by the intent.getAction() method returned value, and then invokes a related method such as startForegroundService().
- In the startForegroundService() method, to make the service object run in the foreground, it will create a Notification object, and then call the startForeground() method to make the service object run as foreground service.
- In the stopForegroundService() method, it will stop the MyForeGroundService service object from the foreground service by invoking the stopForeground(true) method, this will also remove the notification object. Then it will call the stopSelf() method to stop the service object.
- CreateForegroundServiceActivity.java: This is the activity class java file. It will be created when the android app starts. It will listen to the two buttons on-click event, and when one button is clicked, it will start the MyForeGroundService object by creating an Intent object, setting the intent object action, and then calling the startService(intent) method to start the service object. Then the MyForeGroundService object will be created, and its onStartCommand method will be invoked.
2.1 Android Foreground Service Class.
- MyForeGroundService.java
2.2 Main Activity.
- CreateForegroundServiceActivity.java
2.3 Layout XML File.
- activity_create_foreground_service.xml
2.4 Android Manifest Xml File.
- AndroidManifest.xml
2.5 Assign FOREGROUND_SERVICE Permission.
- If your android app os version is higher than or equal to level 26, you need to assign FOREGROUND_SERVICE permission in your android app to avoid crashes.
- To implement this, you should add the below XML snippet in the AndroidManifest.xml file.
Reference
This site uses Akismet to reduce spam. Learn how your comment data is processed.
This gives error for Android O & above versions.
I am facing error as : Developer warning for package “com.xxx.xxx”. Failed to post notification on channel “null”.
Android O Need Notification Channel like that
private fun startForegroundService() <
Log.d(TAG_FOREGROUND_SERVICE, “Start foreground service.”)
// Create notification default intent.
val intent = Intent()
val pendingIntent = PendingIntent.getActivity(this, 0, intent, 0)
val channelId = “NOTIFICATION_CHANNEL_NAME”
// Create notification builder.
val builder = NotificationCompat.Builder(this,channelId)
// Make notification show big text.
val bigTextStyle = NotificationCompat.BigTextStyle()
bigTextStyle.setBigContentTitle(“Music player implemented by foreground service.”)
bigTextStyle.bigText(“Android foreground service is a android service which can run in foreground always, it can be controlled by user via notification.”)
// Set big text style.
builder.setStyle(bigTextStyle)
builder.setWhen(System.currentTimeMillis())
builder.setSmallIcon(R.mipmap.ic_launcher)
val largeIconBitmap = BitmapFactory.decodeResource(resources, R.drawable.abc_ic_ab_back_material)
builder.setLargeIcon(largeIconBitmap)
// Make the notification max priority.
builder.priority = Notification.PRIORITY_MAX
// Make head-up notification.
builder.setFullScreenIntent(pendingIntent, true)
// Add Play button intent in notification.
val playIntent = Intent(this, MyForeGroundService::class.java)
playIntent.action = ACTION_PLAY
val pendingPlayIntent = PendingIntent.getService(this, 0, playIntent, 0)
val playAction = NotificationCompat.Action(android.R.drawable.ic_media_play, “Play”, pendingPlayIntent)
builder.addAction(playAction)
// Add Pause button intent in notification.
val pauseIntent = Intent(this, MyForeGroundService::class.java)
pauseIntent.action = ACTION_PAUSE
val pendingPrevIntent = PendingIntent.getService(this, 0, pauseIntent, 0)
val prevAction = NotificationCompat.Action(android.R.drawable.ic_media_pause, “Pause”, pendingPrevIntent)
builder.addAction(prevAction)
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) <
val channel = NotificationChannel(
channelId, “NOTIFICATION_CHANNEL_NAME”,
NotificationManager.IMPORTANCE_HIGH
).apply <
enableLights(true)
lightColor = Color.DKGRAY
setShowBadge(true)
enableVibration(true)
vibrationPattern = longArrayOf(100, 200, 300, 400, 500, 400, 300, 200, 400)
>
notificationManager.createNotificationChannel(channel)
>
// Build the notification.
val notification = builder.build()
// Start foreground service.
startForeground(1, notification)
>
Источник
Работа с фоновыми задачами в Android 12: переезжаем с foreground service на expedited jobs
С релизом Android 12 приложения, где новая версия операционки будет указана в targetSdkVersion, получат запрет на запуск foreground-сервисов в бэкграунде. В качестве альтернативы Google предлагает WorkManager, который с появлением expedited jobs станет предпочтительным вариантом для запуска высокоприоритетных фоновых задач.
О нём и пойдёт речь в статье — под катом обсудим новые возможности инструмента, подключим его к приложению и реализуем миграцию с foreground-сервиса.
WorkManager и foreground service
Foreground service — это какой-либо сервис, о котором знает пользователь через нотификацию в статус-баре. Например, воспроизведение музыки или работа GPS в картах.
WorkManager — это API для планирования задач, которые будут выполняться, даже если выйти из приложения или перезагрузить устройство.
WorkManager уже давно является приоритетным способом выполнения длительных фоновых задач. К таким относятся синхронизация данных с бэкендом, отправка аналитики, периодическая проверка свободного места в системе с помощью PeriodicWork и так далее.
Но в WorkManager присутствовал и недостаток — не было никаких гарантий, что джоба начнётся незамедлительно после создания. В версии 2.3.0 разработчики добавили для воркеров метод setForegroundAsync(), который, по сути, превращал фоновую задачу в foreground-сервис и позволял немедленно приступить к её выполнению.
Такой подход ничем особо не отличался от разработки foreground-сервиса вручную, когда необходимо создавать объекты Notification и NotificationChannel при таргете выше, чем на Android Nougat.
Сейчас setForegroundAsync() объявлен устаревшим, а при попытке запустить сервис из бэкграунда на выходе будет ForegroundServiceStartNotAllowedException.
Expedited jobs
Этот тип джобов позволяет приложениям выполнять короткие и важные задачи, давая системе больше контроля над доступом к ресурсам. Он находится где-то между foreground-сервисами и привычными джобами WorkManager. От последних их отличает:
минимально отложенное время запуска;
обход ограничений Doze-mode на использование сети;
меньшая вероятность быть «убитыми» системой.
А ещё в них не поддерживаются ограничения по заряду батареи и режиму работы девайса:
У expedited job больший приоритет на ускоренный запуск, поэтому операционная система строже регулирует их количество. Например, если попытаться запланировать джобу при исчерпаном лимите, то сразу вернётся JobScheduler#RESULT_FAILURE.
Если же ограничения по квоте, сети и памяти устройства выполнены, то у джобы будет около минуты на выполнение своих функций. Иногда больше, но это сильно зависит от лимита и общей загруженности системы.
Миграция foreground service на expedited job
Стандартный сервис для выполнения фоновых задач обычно выглядит примерно так:
А запускается так:
Поговорим о том, как перевести этот сервис на expedited job. Происходит это буквально в три простых шага.
1. Подключаем WorkManager к проекту:
2. Создаём класс, наследующийся от Worker (он будет выполнять задачу, которую раньше делал сервис):
3. Создаём WorkRequest и передаём его для запуска в WorkManager:
Здесь есть важный параметр OutOfQuotaPolicy, который отвечает за поведение при невозможности запустить джобу немедленно. Он существует в двух вариантах:
RUN_AS_NON_EXPEDITED_WORK_REQUEST — при заполненной квоте запустится обычная джоба, не expedited.
DROP_WORK_REQUEST — при заполненной квоте запрос на выполнение сразу зафейлится.
На этом, собственно, базовая миграция заканчивается.
Вместо заключения
Переехать на expedited job довольно легко, особенно, если в проекте уже подключен WorkManager.
Сейчас пропала необходимость держать нотификацию в статус-баре, а в условиях выполнения задачи появилась дополнительная гибкость благодаря возможностям WorkManager. Например, теперь можно пережить «смерть» процесса, тонко настраивать ретраи, периодичность выполнения задач и многое другое.
Источник