Введение: вопрос, который проверяет уровень

«Что такое foreground service и чем он отличается от обычного Service?» — редкое собеседование по Android обходится без этого вопроса. И редкий кандидат отвечает на него полностью: про уведомление, типы и разрешения.

Foreground service — часть темы «Service», которую спрашивают на любом уровне: джуну достаточно не словить ANR в onStartCommand, мидлу нужно рассказать про ограничения фона, сеньору — про типы и разрешения Android 14. В моих разборах подготовки это одна из точек, где кандидаты с опытом 1–2 года теряют очки: все слышали слово, но мало кто может объяснить, зачем сервису уведомление и что изменилось в новых версиях Android.

Показательная деталь: ту же тему спрашивают «от обратного». Интервьюер говорит «представьте, что вам нужно писать трекер пробежек» — и кандидат должен сам назвать foreground service, перечислить требования и ограничения. Те, кто знает тему только понаслышке, отвечают «ну, можно же просто Service запустить в фоне» — и сразу теряют баллы, потому что на современном Android такой код даже не заработает.

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

Что такое foreground service: сервис, который видно

Формальное определение из официальной документации: foreground service — это сервис, который выполняет заметные пользователю операции и показывает уведомление в статус-баре, чтобы пользователь понимал, что приложение работает и потребляет ресурсы системы.

Ключевых отличия от обычного Service два:

  • Постоянное уведомление. Сервис обязан показывать его с момента запуска до остановки. Спрятать уведомление нельзя — система этого не позволяет.
  • Повышенный приоритет. Система реже убивает процесс с foreground service, чем процесс с обычным фоновым сервисом, и работа продолжается, даже когда приложение свёрнуто.

Как запомнить определение

Foreground service — это сервис, который «на глазах»: пользователь всегда видит уведомление о его работе. Всё, что происходит незаметно, — уже не его история.

Примеры из документации — музыкальный плеер, который показывает в уведомлении текущий трек, и фитнес-приложение, записывающее пробежку с дистанцией в уведомлении. Общее в обоих сценариях: пользователь не сидит в приложении, но работа должна продолжаться, и он должен об этом знать.

Частая ошибка на собеседовании: «foreground service нужен, чтобы выполнять работу в фоне незаметно». Наоборот — это сервис, который пользователь обязан видеть. Если задача незаметная, ей нужен другой инструмент.

Типы foreground service: обязательное требование Android 14

До Android 13 сервису было достаточно запуститься с уведомлением. Начиная с Android 14 (API 34) правила ужесточились: каждому foreground service нужно объявить тип — и в манифесте, и при вызове startForeground().

Тип задаётся атрибутом android:foregroundServiceType и описывает, чем занимается сервис. Основные типы из списка в документации:

  • dataSync — передача данных;
  • mediaPlayback — воспроизведение медиа;
  • location — геолокация;
  • camera — доступ к камере;
  • microphone — доступ к микрофону;
  • connectedDevice — работа с подключёнными устройствами (BLE и другие).

Типов foreground service

dataSync, mediaPlayback, location, camera, microphone, connectedDevice, phoneCall, mediaProjection, health, remoteMessaging, systemExempted, specialUse — у каждого свои требования по разрешениям.

Приложение, таргетящее Android 14, без типа у сервиса получит MissingForegroundServiceTypeException при вызове startForeground(). А если тип указан, но в манифесте нет разрешения FOREGROUND_SERVICE_<ТИП> — SecurityException. Обе ошибки — классика крэш-репортов после обновления таргета.

Разрешения вида FOREGROUND_SERVICE_CAMERA, FOREGROUND_SERVICE_LOCATION и другие — normal: они выдаются автоматически, но объявлять их в манифесте обязательно. Правила Android 14 подробно описаны в документации об изменениях.

Как запустить foreground service: манифест и код

Покажу минимальный рабочий набор на примере сервиса с типом location. Сначала манифест:

AndroidManifest.xml
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<application>
    <service
        android:name=".LocationTrackingService"
        android:exported="false"
        android:foregroundServiceType="location" />
</application>

Теперь сам сервис. С Android 8 (API 26) уведомление обязано жить в канале (NotificationChannel):

LocationTrackingService.kt
class LocationTrackingService : Service() {

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        startForeground(NOTIFICATION_ID, buildNotification())
        // ... запускаем трекинг
        return START_STICKY
    }

    private fun buildNotification(): Notification {
        val channel = NotificationChannel(
            CHANNEL_ID, "Трекинг", NotificationManager.IMPORTANCE_LOW
        )
        getSystemService(NotificationManager::class.java)
            .createNotificationChannel(channel)

        return NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle("Идёт запись маршрута")
            .setSmallIcon(R.drawable.ic_tracking)
            .setOngoing(true)
            .build()
    }

    override fun onBind(intent: Intent?): IBinder? = null

    companion object {
        private const val NOTIFICATION_ID = 42
        private const val CHANNEL_ID = "tracking"
    }
}

Запуск на Android 8+ — только через ContextCompat.startForegroundService():

MainActivity.kt
val intent = Intent(this, LocationTrackingService::class.java)
ContextCompat.startForegroundService(this, intent)

А если поддерживаете Android 14 и хотите передать тип при запуске — используйте ServiceCompat.startForeground() из androidx.core 1.12+:

LocationTrackingService.kt
ServiceCompat.startForeground(
    this,
    NOTIFICATION_ID,
    buildNotification(),
    ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION
)

Порядок действий важен: runtime-разрешения (например, ACCESS_FINE_LOCATION) должны быть выданы до вызова startForeground(). Система проверяет это и для некоторых типов просто не даст запустить сервис без разрешения.

Ограничения Android 8, 13 и 14: где сервис не запустится

Модель фоновой работы ужесточалась трижды, и на собеседовании выгодно показать, что вы видите всю картину:

  • Android 8 (API 26) — приложение в фоне не может запустить обычный сервис через startService(). Только foreground service — и только через ContextCompat.startForegroundService().
  • Android 13 (API 33) — на показ уведомлений, включая уведомления сервисов, нужно runtime-разрешение POST_NOTIFICATIONS. Если пользователь отказал — заметки о foreground service он видит в Task Manager, но не в шторке уведомлений (разрешение на уведомления).
  • Android 14 (API 34) — обязателен тип сервиса и FOREGROUND_SERVICE_* в манифесте, а для типов camera и location — ещё и runtime-разрешения. Сервис с типом camera нельзя запустить из фона и из BOOT_COMPLETED-ресивера.

Отдельно про запуск из фона: начиная с Android 12 система серьёзно ограничила старт foreground service из фонового процесса — обычно это возможно только в коротком окне после ухода приложения в фон и в ряде исключений. Классическое правило, которое нужно озвучить на собеседовании: запускайте сервис по действию пользователя, а не «на всякий случай».

Ещё одна тема, которую любят проверять, — таймауты. Начиная с Android 15 для сервисов типа dataSync (и нового типа mediaProcessing) введён лимит: суммарно 6 часов работы за сутки, после чего система вызывает Service.onTimeout() — и у сервиса есть несколько секунд, чтобы вызвать stopSelf(). Если этого не сделать, система завершит сервис с ошибкой. Для собеседования достаточно знать, что механика есть, и упомянуть, что длительные задачи лучше раскладывать на этапы, а не держать один сервис вечно.

Когда foreground service не нужен

Главный вопрос, который ловит кандидатов: «А нельзя ли было обойтись без сервиса?» В документации прямо сказано: для многих сценариев существуют специальные API, и они почти всегда лучше собственного foreground service.

  • Отложенная задача, которая должна пережить перезагрузку — WorkManager, а не сервис.
  • Аудио и видео — Media3 / ExoPlayer уже умеют фоновое воспроизведение с уведомлением.
  • Короткая работа при открытом приложении — корутины в ViewModel, сервис не нужен вовсе.
  • Работа, которую пользователь видит и контролирует — вот здесь foreground service оправдан.

Лакмусовая бумажка

Задайте себе вопрос: «Поймёт ли пользователь, что приложение работает, если увидит уведомление?» Нет — ищем другой инструмент. Да — foreground service оправдан.

Готовитесь к собеседованию по Android?

Каждый второй кандидат теряет очки именно на теме фоновой работы: путает Service и Thread, не знает ограничений Android 14, не может объяснить, зачем сервису уведомление. Пришлю бесплатный чек-лист подготовки к собеседованию — конкретные пункты, что закрыть и в каком порядке.

Итоги

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

  • Определение: foreground service — сервис с постоянным уведомлением, выполняющий заметную пользователю работу.
  • Android 14: каждому сервису нужен тип в манифесте и разрешение FOREGROUND_SERVICE_<ТИП>, иначе MissingForegroundServiceTypeException или SecurityException.
  • Современные ограничения: запуск по действию пользователя, runtime-разрешения до startForeground(), а для простых задач — WorkManager или корутины.

Ответ, который закрывает тему

«Foreground service — это сервис с постоянно видимым уведомлением. На Android 14 у каждого сервиса должен быть тип и соответствующее разрешение, а runtime-разрешения выдаются до запуска. Если задача не требует видимого уведомления — это WorkManager или корутина».

Если чувствуете, что тема фоновой работы плавает, а собеседование уже скоро, — не нужно зубрить дальше в одиночку. Напишите в Telegram, разберём вашу ситуацию и составим план подготовки.