Services trong Android
1. Giới thiệu
Service là component chạy background, không có UI, thực hiện long-running operations.
2. Loại Services
| Type | Description | Thread |
|---|---|---|
| Foreground | Visible notification, user aware | Main (cần background thread) |
| Background | No notification, limited | Main |
| Bound | Client-server, IPC | Main |
3. Foreground Service
Khai báo trong Manifest
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
<service
android:name=".MusicService"
android:foregroundServiceType="mediaPlayback"
android:exported="false" />Implementation
class MusicService : Service() {
override fun onCreate() {
super.onCreate()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val notification = createNotification()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
startForeground(
NOTIFICATION_ID,
notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
)
} else {
startForeground(NOTIFICATION_ID, notification)
}
// Do work in background thread
CoroutineScope(Dispatchers.IO).launch {
playMusic()
}
return START_STICKY
}
override fun onBind(intent: Intent?): IBinder? = null
override fun onDestroy() {
super.onDestroy()
stopMusic()
}
private fun createNotification(): Notification {
val channelId = createNotificationChannel()
return NotificationCompat.Builder(this, channelId)
.setContentTitle("Playing Music")
.setContentText("Song name")
.setSmallIcon(R.drawable.ic_music)
.setPriority(NotificationCompat.PRIORITY_LOW)
.build()
}
}Start/Stop Service
// Start
val intent = Intent(context, MusicService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent)
} else {
context.startService(intent)
}
// Stop
context.stopService(Intent(context, MusicService::class.java))4. Bound Service
class DownloadService : Service() {
private val binder = LocalBinder()
inner class LocalBinder : Binder() {
fun getService(): DownloadService = this@DownloadService
}
override fun onBind(intent: Intent): IBinder = binder
fun downloadFile(url: String) {
// Download logic
}
}
// Activity binding
class MainActivity : ComponentActivity() {
private var downloadService: DownloadService? = null
private var isBound = false
private val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
val binder = service as DownloadService.LocalBinder
downloadService = binder.getService()
isBound = true
}
override fun onServiceDisconnected(name: ComponentName?) {
isBound = false
}
}
override fun onStart() {
super.onStart()
Intent(this, DownloadService::class.java).also { intent ->
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
}
override fun onStop() {
super.onStop()
if (isBound) {
unbindService(connection)
isBound = false
}
}
}5. onStartCommand Return Values
| Value | Behavior |
|---|---|
START_STICKY | Recreate if killed, null intent |
START_NOT_STICKY | Don’t recreate |
START_REDELIVER_INTENT | Recreate with last intent |
6. Service Lifecycle
startService() → onCreate() → onStartCommand() → Running → onDestroy()
↑
startService() again → ──────────────────┘
bindService() → onCreate() → onBind() → Bound → onUnbind() → onDestroy()7. Service với Coroutines
class MyService : Service() {
private val job = SupervisorJob()
private val scope = CoroutineScope(Dispatchers.IO + job)
override fun onStartCommand(...): Int {
scope.launch {
doWork()
}
return START_NOT_STICKY
}
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
}8. Android 14+ Restrictions
// Android 14+ cần type cụ thể
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />📝 Tóm tắt
| Khi nào dùng | Solution |
|---|---|
| Long task, user aware | Foreground Service |
| Short task | WorkManager |
| Client-server | Bound Service |
| Periodic sync | WorkManager |
Last updated on