Android Services allow applications to perform long‑running tasks in the background without a user interface. They are critical for use cases such as music playback, file uploads/downloads, sensor monitoring, and IPC (inter‑process communication).
This updated guide on javatechig.com explains how to use Services in Android with modern patterns, lifecycle awareness, foreground execution, and examples in both Kotlin and Java that align with current best practices from Android Developers.
What Is an Android Service?
A Service is an Android component that performs work on behalf of activities or other app components while running in the background. Unlike activities, Services don’t provide a UI but can continue executing even when the app is not visible.
Use Services when tasks must:
- Continue after activity destruction
- Run independently of user interaction
- Perform ongoing work without UI
Types of Android Services
Android supports several Service types:
- Background Service — Runs behind the scenes
- Foreground Service — Visible via a persistent notification
- Bound Service — Allows interaction between clients and service
Modern Android versions impose restrictions on background services; prefer foreground services for ongoing tasks.
Creating a Basic Background Service
Kotlin
class MyBackgroundService : Service() {
override fun onBind(intent: Intent?): IBinder? = null
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Thread {
// Perform background work
}.start()
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
}
}
Java
public class MyBackgroundService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(() -> {
// Background work
}).start();
return START_STICKY;
}
}
Register Service in Manifest
<service
android:name=".MyBackgroundService"
android:enabled="true"
android:exported="false"/>
Include this to allow Android to know about your service.
Starting and Stopping a Service
Start Service
val intent = Intent(this, MyBackgroundService::class.java)
startService(intent)
Stop Service
stopService(intent)
This approach suits simple background tasks.
Foreground Service (Modern Android)
Foreground services must show a persistent notification.
Kotlin Example
class MyForegroundService : Service() {
override fun onBind(intent: Intent?) = null
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val notification = NotificationCompat.Builder(this, "default")
.setContentTitle("Service Running")
.setContentText("Foreground service active")
.setSmallIcon(R.drawable.ic_notification)
.build()
startForeground(1, notification)
// Long‑running work
return START_STICKY
}
}
Java Example
public class MyForegroundService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Notification notification = new NotificationCompat.Builder(this, "default")
.setContentTitle("Service Running")
.setContentText("Foreground service active")
.setSmallIcon(R.drawable.ic_notification)
.build();
startForeground(1, notification);
return START_STICKY;
}
}
Creating Notification Channel (Android 8+)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel("default",
"Service Channel", NotificationManager.IMPORTANCE_LOW)
val manager = getSystemService(NotificationManager::class.java)
manager.createNotificationChannel(channel)
}
Notification channels are required for Android 8 (API 26+) for foreground services.
Bound Service (Client‑Service Interaction)
Bound services allow components to interact with the service.
Kotlin Example
class MyBoundService : Service() {
private val binder = LocalBinder()
inner class LocalBinder : Binder() {
fun getService() = this@MyBoundService
}
override fun onBind(intent: Intent?) = binder
fun getCurrentTime(): String = SimpleDateFormat("HH:mm:ss", Locale.US).format(Date())
}
Java Example
public class MyBoundService extends Service {
private final IBinder binder = new LocalBinder();
public class LocalBinder extends Binder {
MyBoundService getService() {
return MyBoundService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return binder;
}
public String getCurrentTime() {
return new SimpleDateFormat("HH:mm:ss", Locale.US).format(new Date());
}
}
Binding from Activity
Kotlin
private lateinit var service: MyBoundService
private var bound = false
private val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, binder: IBinder?) {
val local = binder as MyBoundService.LocalBinder
service = local.getService()
bound = true
}
override fun onServiceDisconnected(name: ComponentName?) {
bound = false
}
}
bindService(Intent(this, MyBoundService::class.java),
connection, Context.BIND_AUTO_CREATE)
Unbind and Cleanup
Always unbind to avoid leaks:
if (bound) {
unbindService(connection)
bound = false
}
Lifecycle & Restart Behavior
START_STICKY
Service restarts after killed by system — good for persistent tasks.
START_NOT_STICKY
Does not restart — good for one‑off work.
START_REDELIVER_INTENT
System redelivers last intent — good for reliable jobs.
Common Mistakes & Fixes
1. Long Work on Main Thread
Cause: Direct work in onStartCommand()
Fix: Always use background threads or WorkManager.
2. Missing Notification Channel
Cause: Foreground service fails on Android 8+
Fix: Create notification channel before starting.
3. Leaking Service Connections
Cause: Forgetting to unbind
Fix: Unbind in onStop() / onDestroy().
Best Practices (2026 Updated)
- Use WorkManager for scheduled or deferrable background tasks
- Reserve services for real‑time and long‑living operations
- Always respect user privacy and battery usage
- Test on multiple Android versions for compatibility


