Background Service — to komponent Android przeznaczony do wykonywania długotrwałych operacji w tle bez interfejsu użytkownika. W przeciwieństwie do Activity, Service kontynuuje działanie nawet po zminimalizowaniu aplikacji lub przełączeniu się użytkownika do innej aplikacji. Według Android Developers, 2026, istnieją trzy typy serwisów: Started Service, Bound Service i Foreground Service, każdy z własnym cyklem życia i zakresem zastosowania.
Najważniejsze
Background Service (lub po prostu Service) — jeden z czterech głównych komponentów aplikacji Android obok Activity, BroadcastReceiver i ContentProvider. W przeciwieństwie do Activity, Service nie ma interfejsu wizualnego i jest przeznaczony do wykonywania operacji, które powinny być kontynuowane niezależnie od tego, czy aplikacja jest na pierwszym planie, czy nie.
Service działa w głównym wątku (main thread) aplikacji, dlatego wszelkie operacje blokujące w nim wymagają utworzenia osobnego wątku. Jeśli tego nie zrobisz, system wywoła ANR (Application Not Responding). Do prostych operacji w tle Android udostępnia IntentService, który automatycznie tworzy wątek roboczy. W nowoczesnych projektach zaleca się używanie Kotlin-korutyn z CoroutineScope wewnątrz Service do asynchronicznego przetwarzania bez blokowania głównego wątku.
Główne przeznaczenie Service — odtwarzanie muzyki, pobieranie plików, praca z żądaniami sieciowymi, synchronizacja danych i inne zadania, które powinny być kontynuowane po opuszczeniu aplikacji przez użytkownika. Jednak wraz z wydaniem Android 8 programiści muszą świadomie wybierać między typami serwisów, uwzględniając ograniczenia pracy w tle.
Service ma własny cykl życia, który różni się od Activity. Obejmuje cztery kluczowe metody: onCreate, onStartCommand, onBind i onDestroy. Zrozumienie tego cyklu jest niezbędne do prawidłowej realizacji zadań w tle bez wycieków pamięci.
Metoda onCreate wywoływana jest przy tworzeniu serwisu, jednokrotnie w czasie jego życia. Inicjalizuje się w niej zasoby: timery, połączenia z bazą danych, sockety. Metoda onStartCommand wywoływana jest za każdym razem przy wywołaniu startService, co pozwala na przekazywanie poleceń już działającemu serwisowi. Wartość zwracana określa zachowanie systemu przy restarcie.
class DownloadService : Service() {
override fun onCreate() {
super.onCreate()
initializeDownloader()
}
override fun onStartCommand(
intent: Intent?,
flags: Int,
startId: Int
): Int {
downloadFile(intent?.getStringExtra("url"))
return START_STICKY
}
override fun onBind(intent: Intent): IBinder? = null
}
onBind wywoływany jest przy wiązaniu serwisu przez bindService i zwraca obiekt IBinder do interakcji z klientem. Ta metoda używana jest tylko dla Bound Service. onDestroy — ostatnie wywołanie przed zniszczeniem serwisu. W nim zwalniane są wszystkie zasoby, zatrzymane wątki i anulowane zadania.
Android oferuje trzy typy Service, z których każdy przeznaczony jest do swojego scenariusza. Wybór niewłaściwego typu może prowadzić do niestabilnej pracy aplikacji lub zwiększonego zużycia baterii.
Started Service uruchamiany jest wywołaniem startService i działa do momentu wywołania stopSelf lub stopService. Nadaje się do zadań, które muszą być wykonane natychmiast: wysyłanie analityki, przetwarzanie obrazu, pobieranie pojedynczego pliku. Po zakończeniu pracy serwis zatrzymuje się samodzielnie.
Bound Service udostępnia interfejs klient-serwer, umożliwiając Activity, Fragment lub innemu komponentowi interakcję z serwisem. Serwis żyje, dopóki istnieje co najmniej jeden związany klient. Gdy wszyscy klienci się odwiążą, serwis jest niszczony. Bound Service jest wygodny do zadań wymagających dwukierunkowej komunikacji: odtwarzacz muzyki, nawigacja.
Foreground Service — to Started Service ze stałym powiadomieniem na pasku statusu. System uważa taki serwis za aktywny i nie zabija go nawet przy braku pamięci. Foreground Service jest obowiązkowy do odtwarzania muzyki, nagrywania audio, śledzenia lokalizacji i innych zadań ważnych dla użytkownika.
| Parametr | Started | Bound | Foreground |
|---|---|---|---|
| Uruchomienie | startService | bindService | startForeground |
| Życie | do stopSelf | dopóki są klienci | do stopForeground |
| Powiadomienie | nie | nie | wymagane |
| Zabijany | tak | tak | nie |
| Przykład | pobieranie | odtwarzacz | muzyka |
Tworzenie serwisu rozpoczyna się od zadeklarowania klasy dziedziczącej po Service i zarejestrowania jej w AndroidManifest.xml. Bez rejestracji w manifeście system nie będzie mógł uruchomić serwisu, a każde wywołanie startService doprowadzi do wyjątku.
// Rejestracja w AndroidManifest.xml
@SuppressLint("ForegroundServiceType")
class SyncService : Service() {
override fun onStartCommand(
intent: Intent?,
flags: Int,
startId: Int
): Int {
startForeground(
NOTIFICATION_ID,
createNotification()
)
performSync(intent)
return START_NOT_STICKY
}
}
Do uruchomienia serwisu z Activity lub Fragment używa się Intent z jawnym wskazaniem klasy serwisu. Od Android 8 dla Foreground Service wymagane jest zezwolenie FOREGROUND_SERVICE w manifeście.
// Uruchamianie Started Service
val intent = Intent(this, SyncService::class.java)
intent.putExtra("action", "sync")
startService(intent)
// Uruchamianie Foreground Service (Android 8+)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent)
} else {
startService(intent)
}
Od Android 8 (API 26) Google wprowadził ścisłe ograniczenia dotyczące serwisów tła. Uruchomienie Service w tle (gdy aplikacja nie jest na pierwszym planie) jest dozwolone tylko w wyjątkowych przypadkach: po otrzymaniu push-powiadomienia, po uruchomieniu urządzenia lub przez JobScheduler.
Do długotrwałych zadań, które nie wymagają natychmiastowego wykonania, zaleca się używanie WorkManager lub JobScheduler. Jeśli aplikacja naprawdę potrzebuje działającego serwisu, jedynym sposobem jest Foreground Service z powiadomieniem widocznym dla użytkownika. Uruchomienie serwisu bez powiadomienia w tle zostanie zignorowane przez system.
JobIntentService — to wyspecjalizowana klasa, która pojawiła się w support library do pracy na Android 5+. Łączy ona zachowanie IntentService (automatyczny wątek roboczy, sekwencyjne przetwarzanie) z planowaniem przez JobScheduler. Na Android 8+ JobIntentService używa JobScheduler pod maską, a na starszych wersjach — zwykłego Service. Pozwala to jednolicie obsługiwać zadania w tle bez dodatkowych sprawdzeń wersji Android.
class UploadJobService : JobIntentService() {
companion object {
private const val JOB_ID = 1000
fun enqueueWork(context: Context, work: Intent) {
enqueueWork(
context,
UploadJobService::class.java,
JOB_ID,
work
)
}
}
override fun onHandleWork(intent: Intent) {
val fileUri = intent.getStringExtra("file_uri")
// Wykonywane w wątku tła
uploadFile(fileUri)
}
}
Jednym z częstych problemów przy pracy z Background Service są wycieki pamięci. Ponieważ Service może żyć dłużej niż Activity, referencje do Activity wewnątrz Service (przez listener, callback lub broadcast) prowadzą do braku możliwości zwolnienia pamięci dla komponentów UI. Zaleca się używanie WeakReference, ViewModel lub LiveData do komunikacji Service z UI. W onDestroy należy anulować wszystkie subskrypcje, zatrzymać wątki i zamknąć kursory.
Wybór między Background Service a WorkManager zależy od scenariusza. Service nadaje się do zadań, które muszą być wykonane natychmiast i ciągle: odtwarzanie muzyki, nagrywanie audio, śledzenie GPS. WorkManager jest lepszy do odroczonych, gwarantowanych zadań: synchronizacja, wysyłanie analityki, przesyłanie logów. WorkManager przetrwa ponowne uruchomienie urządzenia, a Service — nie. Service może być Foreground z powiadomieniem, a WorkManager działa cicho w tle. W praktyce programiści łączą oba podejścia: Foreground Service do krytycznych zadań użytkownika i WorkManager do obsługi w tle.
Android 12 wprowadził flagę android:foregroundServiceType, która wymaga określenia typu usługi: dataSync, camera, connectedDevice, location, mediaPlayback i inne. Nieprawidłowe określenie typu prowadzi do wyjątku przy uruchomieniu. Ta praktyka czyni Background Service bardziej przejrzystym dla użytkownika i systemu.
Prawidłowa rejestracja Service w manifeście obejmuje atrybuty exported (dostępność dla aplikacji zewnętrznych), foregroundServiceType (typ usługi tła na Android 12+) i permission. Dla Bound Service należy również zadeklarować android:permission="android.permission.BIND_JOB_SERVICE" dla JobIntentService. Bez rejestracji w manifeście każde wywołanie startService lub bindService zakończy się wyjątkiem, dlatego sprawdzenie manifestu jest pierwszym krokiem przy diagnozowaniu problemów z Service.
Często zadawane pytania
Service działa w głównym wątku (UI Thread) aplikacji. Każda operacja blokująca wewnątrz onStartCommand lub onHandleIntent musi być przeniesiona do osobnego wątku lub korutyny, w przeciwnym razie system wywoła ANR po 5 sekundach.
IntentService — to dziedzic Service, który automatycznie tworzy wątek roboczy i przetwarza polecenia sekwencyjnie. Po zakończeniu ostatniego zadania IntentService zatrzymuje się sam. Od Android 8 IntentService jest uznawany za przestarzały na rzecz JobIntentService lub WorkManager.
Uruchomienie Started Service z tła na Android 12 jest zabronione. Wyjątkiem jest Foreground Service z zadeklarowanym foregroundServiceType w manifeście i ważnym powiadomieniem. Dozwolony jest również krótki start po otrzymaniu wiadomości FCM o wysokim priorytecie.
Istnieją trzy sposoby: BroadcastReceiver z lokalnym broadcast, mechanizm Messenger przez Handler, oraz LiveData/Flow w architekturze MVVM z wspólnym ViewModel. Dla Bound Service używa się IBinder z bezpośrednim wywołaniem metod.
Jeśli Service został uruchomiony z flagą START_STICKY, system uruchomi go ponownie po zniszczeniu procesu z powodu braku pamięci. Flaga START_NOT_STICKY oznacza, że system nie będzie uruchamiać serwisu ponownie. START_REDELIVER_INTENT jest podobny do START_STICKY, ale przekazuje ostatni Intent.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również