Background Service is an Android component designed for performing long-running operations in the background without a user interface. Unlike Activity, Service continues to work even after the application is minimized or the user switches to another app. According to Android Developers, 2026, there are three types of services: Started Service, Bound Service, and Foreground Service, each with its own lifecycle and scope of use.
Key Takeaways
Background Service (or simply Service) is one of the four fundamental components of an Android application, alongside Activity, BroadcastReceiver, and ContentProvider. Unlike Activity, Service does not have a visual interface and is designed for performing operations that must continue regardless of whether the application is in the foreground or not.
Service runs on the main thread of the application, so any blocking operations inside it require creating a separate thread. If this is not done, the system will throw ANR (Application Not Responding). For simple background operations, Android provides IntentService, which automatically creates a worker thread. In modern projects, it is recommended to use Kotlin coroutines with CoroutineScope inside the Service for asynchronous processing without blocking the main thread.
The main purpose of Service is playing music, downloading files, handling network requests, data synchronization, and other tasks that must continue after the user leaves the application. However, since Android 8, developers must consciously choose between service types, taking into account background work restrictions.
Service has its own lifecycle, which differs from Activity. It includes four key methods: onCreate, onStartCommand, onBind, and onDestroy. Understanding this cycle is essential for correctly implementing background tasks without memory leaks.
The onCreate method is called when the service is created, once during its lifetime. Resources such as timers, database connections, and sockets are initialized here. The onStartCommand method is called every time startService is invoked, allowing commands to be sent to an already running service. The return value determines the system's behavior on restart.
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 is called when binding a service via bindService and returns an IBinder object for client interaction. This method is used only for Bound Service. onDestroy is the last call before the service is destroyed. All resources, stopped threads, and cancelled tasks are released here.
Android offers three types of Service, each designed for its own scenario. Choosing the wrong type can lead to unstable application behavior or battery drain.
Started Service is launched by calling startService and runs until it calls stopSelf or stopService. It is suitable for tasks that need to be executed immediately: sending analytics, processing an image, downloading a single file. After completing its work, the service stops itself.
Bound Service provides a client-server interface, allowing an Activity, Fragment, or other component to interact with the service. The service lives as long as there is at least one bound client. When all clients unbind, the service is destroyed. Bound Service is convenient for tasks requiring bidirectional communication: music player, navigation.
Foreground Service is a Started Service with a persistent notification in the status bar. The system considers such a service active and does not kill it even under low memory. Foreground Service is mandatory for music playback, audio recording, location tracking, and other tasks important to the user.
| Parameter | Started | Bound | Foreground |
|---|---|---|---|
| Launch | startService | bindService | startForeground |
| Lifetime | until stopSelf | while clients exist | until stopForeground |
| Notification | no | no | required |
| Killable | yes | yes | no |
| Example | downloading | player | music |
Creating a service begins with declaring a class that inherits from Service and registering it in AndroidManifest.xml. Without manifest registration, the system will not be able to start the service, and any call to startService will result in an exception.
// Registration in 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
}
}
To start a service from an Activity or Fragment, an Intent with an explicit service class reference is used. Starting with Android 8, Foreground Service requires the FOREGROUND_SERVICE permission in the manifest.
// Starting a Started Service
val intent = Intent(this, SyncService::class.java)
intent.putExtra("action", "sync")
startService(intent)
// Starting a Foreground Service (Android 8+)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent)
} else {
startService(intent)
}
Starting with Android 8 (API 26), Google introduced strict restrictions on background services. Background Service startup (when the app is not in the foreground) is allowed only in exceptional cases: upon receiving a push notification, after device boot, or via JobScheduler.
For long-running tasks that do not require immediate execution, it is recommended to use WorkManager or JobScheduler. If an app genuinely needs a running service, the only way is a Foreground Service with a notification visible to the user. Starting a service without a notification in the background will be ignored by the system.
JobIntentService is a specialized class that appeared in the support library for working on Android 5+. It combines the behavior of IntentService (automatic worker thread, sequential processing) with scheduling via JobScheduler. On Android 8+, JobIntentService uses JobScheduler under the hood, and on older versions, a regular Service. This allows uniform handling of background tasks without additional Android version checks.
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")
// Runs in a background thread
uploadFile(fileUri)
}
}
One of the common problems when working with Background Service is memory leaks. Since a Service can outlive an Activity, references to Activity inside the Service (via listener, callback, or broadcast) prevent garbage collection of UI components. It is recommended to use WeakReference, ViewModel, or LiveData for Service-to-UI communication. In onDestroy, be sure to cancel all subscriptions, stop threads, and close cursors.
The choice between Background Service and WorkManager depends on the scenario. Service is suitable for tasks that must run immediately and continuously: music playback, audio recording, GPS tracking. WorkManager is better for deferred, guaranteed tasks: synchronization, analytics sending, log uploading. WorkManager survives device reboots, while Service does not. Service can be a Foreground with a notification, while WorkManager works quietly in the background. In practice, developers combine both approaches: Foreground Service for critical user-facing tasks and WorkManager for background maintenance.
Android 12 introduced the android:foregroundServiceType flag, which requires specifying the service type: dataSync, camera, connectedDevice, location, mediaPlayback, and others. Incorrect type specification leads to an exception at startup. This practice makes Background Service more transparent for both the user and the system.
Proper Service registration in the manifest includes the exported attribute (accessibility to external apps), foregroundServiceType (background service type on Android 12+), and permission. For Bound Service, you also need to declare android:permission="android.permission.BIND_JOB_SERVICE" for JobIntentService. Without manifest registration, any startService or bindService call will throw an exception, so manifest checking is the first step in diagnosing Service-related issues.
Frequently Asked Questions
Service runs on the main thread (UI Thread) of the application. Any blocking operation inside onStartCommand or onHandleIntent must be moved to a separate thread or coroutine, otherwise the system will throw an ANR after 5 seconds.
IntentService is a subclass of Service that automatically creates a worker thread and processes commands sequentially. After completing the last task, IntentService stops itself. Starting with Android 8, IntentService is considered deprecated in favor of JobIntentService or WorkManager.
Starting a Started Service from the background on Android 12 is prohibited. The exception is a Foreground Service with a declared foregroundServiceType in the manifest and a valid notification. A short startup after receiving a high-priority FCM message is also allowed.
There are three methods: BroadcastReceiver with local broadcast, the Messenger mechanism via Handler, and LiveData/Flow in MVVM architecture with a shared ViewModel. For Bound Service, IBinder is used with direct method calls.
If a Service was started with the START_STICKY flag, the system will restart it after the process is killed due to low memory. The START_NOT_STICKY flag means the system will not restart the service. START_REDELIVER_INTENT is similar to START_STICKY but delivers the last Intent.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also