- Foreground Services in Android
- Explanation
- Работа с фоновыми задачами в Android 12: переезжаем с foreground service на expedited jobs
- WorkManager и foreground service
- Expedited jobs
- Миграция foreground service на expedited job
- Вместо заключения
- 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.
Foreground Services in Android
Jun 10, 2020 · 4 min read
In this tutorial, I’ll talk about the foreground service on Android. We will go through it’s implementation and some pointers I’d like to talk about. So let’s get started.
So what is a foreground service?
Official Android documentation defines a foreground service as
A foreground service performs some operation that is noticeable to the user. For example, an audio app would use a foreground service to play an audio track. Foreground services must display a Notification. Foreground services continue running even when the user isn’t interacting with the app.
A foreground service is a service that the user is active l y aware of and isn’t a candidate for the system to kill when low on memory. A foreground service must provide a notification for the status bar, which is placed under the Ongoing heading. This means that the notification cannot be dismissed unless the service is either stopped or removed from the foreground.
The real-world use cases of foreground services can be a Google Map app that narrates directions, or a music app that constantly streams music, even if the app is in the background.
Creating a Foreground Service takes the following steps.
- Start a Service, a Sticky Service that sticks to the Application.
- Display a notification to let Android know about the foreground service
- Once your notification is displayed, implement the logic for the Foreground Service. This is where you stream the music or map directions
- Update the notification respectively. Note: Until the Foreground service is completely killed, notification has to be displayed
- Once the work is done, kill your Service.
We start by creating our service class that extends the Service class
Override the onStartCommand to start a notification. If you miss this step, Android will kill the service after around a 1 minute of execution time.
Explanation
Jumping straight to the explanation of what we have done here. There are 2 important things to know about the Foreground Service.
- As mentioned before, the foreground services in Android cannot be started without passing a Notification to it.
- Service Lifecycle decides if a Service should be running or not. When it comes to overriding the onStartCommand() method, we are required to provide return modes which are:
- START_STICKY: If this service’s process is killed while it is started (after returning from onStartCommand(Intent, int, int) ), then leave it in the started state but don’t retain this delivered intent. This mode makes sense for things that will be explicitly started and stopped to run for arbitrary period of time, such as a service performing background music playback.
- START_NOT_STICKY: If this service’s process is killed while it is started (after returning from onStartCommand(Intent, int, int) ), and there are no new start intents to deliver to it, then take the service out of the started state and don’t recreate until a future explicit call to Context#startService . This mode makes sense for things that want to do some work as a result of being started but can be stopped when under memory pressure and will explicitly start themselves again later to do more work. An example of such a service would be one that polls for data from a server: it could schedule an alarm to poll every N minutes by having the alarm start its service.
- START_REDELIVER_INTENT: if this service’s process is killed while it is started (after returning from onStartCommand(Intent, int, int) ), then it will be scheduled for a restart and the last delivered Intent re-delivered to it again via onStartCommand(Intent, int, int) . This Intent will remain scheduled for redelivery until the service calls stopSelf(int) with the start ID provided to onStartCommand(Intent, int, int) . The service will not receive a onStartCommand(android.content.Intent, int, int) call with a null Intent because it will only be restarted if it is not finished processing all Intents sent to it (and any such pending events will be delivered at the point of restart).
And lastly, for apps that are targeting Android API level P and beyond, put this in your AndroidManifest.xml
And also, register your service in the same file
Once you have your service class setup, all you need to do is call the startService method from your Activity/Fragment and viola! A notification will popup. In order to stop the service, call the stopService function.
- If you call startService from the background, it will throw an IllegalStateException and crash
- You can use the startForegroundService (or ContextCompat.startForegroundService) to let the system know about the nature of your service. If you do this, you need to call the startForeground method from your service class within 5 seconds
Check a complete sample out on my Github Repository, I will post more articles containing background work, work scheduler, etc.
Источник
Работа с фоновыми задачами в 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. Например, теперь можно пережить «смерть» процесса, тонко настраивать ретраи, периодичность выполнения задач и многое другое.
Источник
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)
>
Источник