Service
Service는 안드로이드의 4대 컴포넌트 중 하나로 백그라운드 작업을 위한 컴포넌트입니다.
얼핏 백그라운드 스레드와 비슷해 보이지만 Service는 워커 쓰레드가 아닌 메인 쓰레드에서 실행됩니다.
서비스는 Started Service와 Bound Service 두 가지 형태로 실행됩니다.
Started Service
- 서비스를 호출한 액티비티와는 관계 없이 독립적으로 동작하고 startService() 메서드로 호출합니다.
- 독립적으로 동작하기 때문에 액티비티의 종료에 영향을 받지 않습니다.
- 클래스의 인스턴스를 오직 하나만 생성해서 유지하는 디자인 패턴인 Singleton으로 동작합니다.

Bound Service
- 서비스가 액티비티에 바인드되며 액티비티와 값을 주고받습니다.
- bindService() 메서드로 호출하며 하나의 Bound Service를 여러 액티비티가 사용할 수 있습니다.
- 바인드된 액티비티가 모두 종료되면 서비스도 종료됩니다.

Service 만들기
1. 서비스 클래스 생성
Service 클래스를 상속받아 클래스를 생성합니다.
// Started Service
class MyService : Service() {
// 서비스 시작
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return super.onStartCommand(intent, flags, startId)
}
// 서비스 종료
override fun onDestroy() {
super.onDestroy()
}
}
// Bound Service
class MyService : Service() {
inner class MyServiceBinder : Binder() {
// getService() 메서드를 통해 서비스에 접근
fun getService(): MyService {
return this@MyService
}
}
val binder = MyServiceBinder()
// 서비스 연결
override fun onBind(intent: Intent): IBinder {
return binder
}
// 액티비티에서 서비스의 메서드를 직접 호출하여 사용 가능
fun serviceMessage(): String {
return "Hello! I am Service!"
}
}
2. 서비스 등록
Service는 AndroidManifest에 등록되어 있어야 사용할 수 있습니다.
<service
android:name=".MyService"
android:enabled="true"
android:exported="true">
</service>
3. 서비스 실행과 종료
Started Service에서는 intent에 인텐트 액션을 넣어 startService() 메서드를 통해 서비스를 시작합니다.
// 서비스 시작
fun serviceStart() {
val intent = Intent(this, MyService::class.java)
.apply { action = MyService.ACTION_START }
startService(intent)
}
// 서비스 종료
fun serviceStop() {
val intent = Intent(this, MyService::class.java)
stopService(intent)
}
Bound Service를 액티비티와 연결하기 위해선 Binder와 ServiceConnection을 생성해야 합니다.
onServiceConnected() 메서드는 서비스가 연결되면 호출되고 onServiceDisconnected() 메서드는 서비스가 비정상적으로 종료되었을 때 호출됩니다.
따라서, 현재 서비스가 연결되어 있는지를 확인하는 로직이 필요합니다.
var myService: MyService? = null
var isService = false // 현재 서비스가 동작하는지 확인하는 변수
val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
val binder = service as MyService.MyBinder
myService = binder.getService()
isService = true
}
override fun onServiceDisconnected(name: ComponentName) {
isService = false
}
}
fun serviceBind(view: View) {
val intent = Intent(this, MyService::class.java)
// 서비스가 생성되어 있지 않으면 생성 후 바인딩을 하고 생성되어 있으면 바로 바인딩
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
fun serviceUnbind(view: View) {
if (isService) { // 현재 서비스 실행 중일 때
unbindService(connection) // 바인드 해제
isService = false
}
}
Foreground Service
- 기본적인 서비스는 모두 포그라운드가 아닌 백그라운드에서 이뤄집니다.
- Foreground Service는 사용자에게 알림을 통해 현재 작업이 진행 중이라는 것을 알려줘야 합니다.
- Background Service는 앱이 꺼지거나 가용 자원이 부족하면 시스템에 의해 제거될 수 있지만, Foreground Service는 사용자가 알림을 통해 서비스가 동작하고 있다는 것을 인지하고 있기 때문에 가용 자원 부족과 같은 이유로 종료되지 않습니다.
Foreground Service 구현하기
1. Manifest에 권한 명시 및 서비스 등록
Foreground Service를 사용하기 위해서는 AndroidManifest에 해당 권한을 명시해야 합니다.
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application
// ...
<service
android:name=".MyForegroundService"
android:enabled="true"
android:exported="true">
</service>
// ...
</application>
2. Foreground Service 클래스 생성
Foreground Service를 사용하기 위해서는 상태 바에 알림을 띄워야 합니다.
먼저 알림 채널을 만든 후에 startForeground() 메서드를 통해 알림을 생성합니다.
class MyForegroundService : Service() {
val CHANNEL_ID = "ForegroundChannel" // 상태 바에 뜰 알림 이름
// ...
override fun onBind(intent: Intent): IBinder {
return Binder() // 오류를 막기 위해 비어 있는 Binder() 리턴
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
createNotificationChannel() // 알림 채널 생성
val notification: Notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Foreground Service")
.setSmallIcon(R.drawable.ic_notification_icon)
.build()
startForeground(1, notification) // 알림 생성
return super.onStartCommand(intent, flags, startId)
}
// Foreground 서비스에 사용할 알림을 생성하기 전에 알림 채널을 생성하는 메서드
// 모든 알림은 오레오 버전 이후로 채널 단위로 동작합니다.
fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val serviceChannel = NotificationChannel(
CHANNEL_ID,
"Foreground Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
)
val notificationManager = getSystemService(NotificationManager::class.java)
notificationManager.createNotificationChannel(serviceChannel)
}
}
}
3. Foreground Service 실행과 종료
Foreground Service는 ContextCompat.startForegroundService()를 통해 실행합니다.
// Foreground Service 실행
val intent = Intent(this, MyForegroundService::class.java)
ContextCompat.startForegroundService(this, intent)
// Foreground Service 종료
val intent = Intent(this, MyForegroundService::class.java)
stopService(intent)
'안드로이드 > 개념' 카테고리의 다른 글
[Android] @JvmOverloads (0) | 2023.08.06 |
---|---|
[Android] Broadcast Receiver (0) | 2023.08.01 |
[Android] sealed class (0) | 2023.07.30 |
[Android] 런타임 권한 요청하기 (0) | 2023.07.28 |
[Android] registerForActivityResult 사용하기 (0) | 2023.07.26 |
Service
Service는 안드로이드의 4대 컴포넌트 중 하나로 백그라운드 작업을 위한 컴포넌트입니다.
얼핏 백그라운드 스레드와 비슷해 보이지만 Service는 워커 쓰레드가 아닌 메인 쓰레드에서 실행됩니다.
서비스는 Started Service와 Bound Service 두 가지 형태로 실행됩니다.
Started Service
- 서비스를 호출한 액티비티와는 관계 없이 독립적으로 동작하고 startService() 메서드로 호출합니다.
- 독립적으로 동작하기 때문에 액티비티의 종료에 영향을 받지 않습니다.
- 클래스의 인스턴스를 오직 하나만 생성해서 유지하는 디자인 패턴인 Singleton으로 동작합니다.

Bound Service
- 서비스가 액티비티에 바인드되며 액티비티와 값을 주고받습니다.
- bindService() 메서드로 호출하며 하나의 Bound Service를 여러 액티비티가 사용할 수 있습니다.
- 바인드된 액티비티가 모두 종료되면 서비스도 종료됩니다.

Service 만들기
1. 서비스 클래스 생성
Service 클래스를 상속받아 클래스를 생성합니다.
// Started Service class MyService : Service() { // 서비스 시작 override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { return super.onStartCommand(intent, flags, startId) } // 서비스 종료 override fun onDestroy() { super.onDestroy() } }
// Bound Service class MyService : Service() { inner class MyServiceBinder : Binder() { // getService() 메서드를 통해 서비스에 접근 fun getService(): MyService { return this@MyService } } val binder = MyServiceBinder() // 서비스 연결 override fun onBind(intent: Intent): IBinder { return binder } // 액티비티에서 서비스의 메서드를 직접 호출하여 사용 가능 fun serviceMessage(): String { return "Hello! I am Service!" } }
2. 서비스 등록
Service는 AndroidManifest에 등록되어 있어야 사용할 수 있습니다.
<service android:name=".MyService" android:enabled="true" android:exported="true"> </service>
3. 서비스 실행과 종료
Started Service에서는 intent에 인텐트 액션을 넣어 startService() 메서드를 통해 서비스를 시작합니다.
// 서비스 시작 fun serviceStart() { val intent = Intent(this, MyService::class.java) .apply { action = MyService.ACTION_START } startService(intent) } // 서비스 종료 fun serviceStop() { val intent = Intent(this, MyService::class.java) stopService(intent) }
Bound Service를 액티비티와 연결하기 위해선 Binder와 ServiceConnection을 생성해야 합니다.
onServiceConnected() 메서드는 서비스가 연결되면 호출되고 onServiceDisconnected() 메서드는 서비스가 비정상적으로 종료되었을 때 호출됩니다.
따라서, 현재 서비스가 연결되어 있는지를 확인하는 로직이 필요합니다.
var myService: MyService? = null var isService = false // 현재 서비스가 동작하는지 확인하는 변수 val connection = object : ServiceConnection { override fun onServiceConnected(name: ComponentName, service: IBinder) { val binder = service as MyService.MyBinder myService = binder.getService() isService = true } override fun onServiceDisconnected(name: ComponentName) { isService = false } } fun serviceBind(view: View) { val intent = Intent(this, MyService::class.java) // 서비스가 생성되어 있지 않으면 생성 후 바인딩을 하고 생성되어 있으면 바로 바인딩 bindService(intent, connection, Context.BIND_AUTO_CREATE) } fun serviceUnbind(view: View) { if (isService) { // 현재 서비스 실행 중일 때 unbindService(connection) // 바인드 해제 isService = false } }
Foreground Service
- 기본적인 서비스는 모두 포그라운드가 아닌 백그라운드에서 이뤄집니다.
- Foreground Service는 사용자에게 알림을 통해 현재 작업이 진행 중이라는 것을 알려줘야 합니다.
- Background Service는 앱이 꺼지거나 가용 자원이 부족하면 시스템에 의해 제거될 수 있지만, Foreground Service는 사용자가 알림을 통해 서비스가 동작하고 있다는 것을 인지하고 있기 때문에 가용 자원 부족과 같은 이유로 종료되지 않습니다.
Foreground Service 구현하기
1. Manifest에 권한 명시 및 서비스 등록
Foreground Service를 사용하기 위해서는 AndroidManifest에 해당 권한을 명시해야 합니다.
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <application // ... <service android:name=".MyForegroundService" android:enabled="true" android:exported="true"> </service> // ... </application>
2. Foreground Service 클래스 생성
Foreground Service를 사용하기 위해서는 상태 바에 알림을 띄워야 합니다.
먼저 알림 채널을 만든 후에 startForeground() 메서드를 통해 알림을 생성합니다.
class MyForegroundService : Service() { val CHANNEL_ID = "ForegroundChannel" // 상태 바에 뜰 알림 이름 // ... override fun onBind(intent: Intent): IBinder { return Binder() // 오류를 막기 위해 비어 있는 Binder() 리턴 } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { createNotificationChannel() // 알림 채널 생성 val notification: Notification = NotificationCompat.Builder(this, CHANNEL_ID) .setContentTitle("Foreground Service") .setSmallIcon(R.drawable.ic_notification_icon) .build() startForeground(1, notification) // 알림 생성 return super.onStartCommand(intent, flags, startId) } // Foreground 서비스에 사용할 알림을 생성하기 전에 알림 채널을 생성하는 메서드 // 모든 알림은 오레오 버전 이후로 채널 단위로 동작합니다. fun createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val serviceChannel = NotificationChannel( CHANNEL_ID, "Foreground Service Channel", NotificationManager.IMPORTANCE_DEFAULT ) val notificationManager = getSystemService(NotificationManager::class.java) notificationManager.createNotificationChannel(serviceChannel) } } }
3. Foreground Service 실행과 종료
Foreground Service는 ContextCompat.startForegroundService()를 통해 실행합니다.
// Foreground Service 실행 val intent = Intent(this, MyForegroundService::class.java) ContextCompat.startForegroundService(this, intent) // Foreground Service 종료 val intent = Intent(this, MyForegroundService::class.java) stopService(intent)
'안드로이드 > 개념' 카테고리의 다른 글
[Android] @JvmOverloads (0) | 2023.08.06 |
---|---|
[Android] Broadcast Receiver (0) | 2023.08.01 |
[Android] sealed class (0) | 2023.07.30 |
[Android] 런타임 권한 요청하기 (0) | 2023.07.28 |
[Android] registerForActivityResult 사용하기 (0) | 2023.07.26 |