[Android/Kotlin] 서비스(Service) 컴포넌트 정리
안드로이드 4대 컴포넌트
- 액티비티(Activity)
- 브로드캐스트 리시버(Broadcast Receiver)
- 서비스(Service)
- 콘텐츠 프로바이더(Content Provider)
서비스(Service)
- 오래 걸리는 작업을 백그라운드에서 처리할 수 있게 해주는 컴포넌트.
- 서비스에 화면을 구현하지 않는다.
- 시스템에서 생명주기를 관리한다.
- 안드로이드 8버전 부터 백그라운드 작업에 제약이 생김.
서비스 생성, 실행 순서
1. [MyService.kt] Service 클래스를 상속받아서 서비스 컴포넌트 작성
package com.example.프로젝트명
import android.app.Service
import android.content.Intent
import android.os.IBinder
class MyService : Service() {
override fun onBind(intent: Intent): IBinder {
TODO("Return the communication channel to the service.")
}
}
2. [MyService.kt] onBind() 함수 오버라이딩, IBinder 인터페이스를 구현한 객체를 반환하도록 작성
*IBinder 인터페이스를 구현한 클래스가 Binder이기 때문에, Binder 클래스를 상속하는 것으로 가능. Binder 클래스를 상속받는 MyBinder 클래스를 선언해서 액티비티-서비스 간에 전달할 필드, 메서드 등을 선언해 둔다. 어쨌든 액티비티-서비스 간에 오가는 건 IBinder 인터페이스를 구현한 객체 하나 뿐. 그 안에 필요한 여러 기능을 담아야 한다.
package com.example.androidlab
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
class MyService : Service() {
class MyBinder : Binder() {
fun funA(arg: Int) {
}
fun funB(arg: Int): Int {
return arg * arg
}
}
override fun onBind(intent: Intent): IBinder {
return Binder()
}
}
3. [AndroidManifest.xml] 서비스 컴포넌트 등록
<service
android:name=".MyService"
android:enabled="true"
android:exported="true"></service>
4. [MainActivity.kt] ServiceConnection인터페이스를 구현한 객체 생성
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// ServiceConnection 객체 생성
val connection: ServiceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
TODO("Not yet implemented")
}
override fun onServiceDisconnected(name: ComponentName?) {
TODO("Not yet implemented")
}
}
}
}
5. [MainActivity.kt] onServiceConnected(), onServiceDisconnected() 함수 오버라이딩
- onServiceConnected() : bindService() 함수로 서비스를 구동할 때 자동으로 호출된다.
- onServiceDisconnected() : unbindService() 함수로 서비스를 종료할 때 자동으로 호출된다.
var serviceBinder: MyService.MyBinder
// ServiceConnection 객체 생성
val connection: ServiceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
serviceBinder = service as MyService.MyBinder
}
override fun onServiceDisconnected(name: ComponentName?) {
TODO("Not yet implemented")
}
}
6. [MainActivity.kt] 서비스를 인텐트에 담아서 실행
// 서비스 실행
val intent = Intent(this, MyService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
7. [MainActivity.kt / MyService.kt] bindService() 함수로 서비스를 실행하면 서비스의 onBind() 함수가 실행된다.
onBind() 함수는 Service에서 구현한 대로 IBinder인터페이스를 구현한 객체를 반환한다.
8. [MainActivity.kt] onBind()에서 반환된 Binder객체는 ServiceConnection인터페이스를 구현한 객체의 onServiceConnected() 함수의 매개변수로 받을 수 있다.
var serviceBinder: MyService.MyBinder
val connection: ServiceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
serviceBinder = service as MyService.MyBinder
}
override fun onServiceDisconnected(name: ComponentName?) {
TODO("Not yet implemented")
}
}
- onServiceConnected(name: ComponentName?, service: IBinder?) 에서 service 매개변수가 서비스에서 반환된 Binder 객체이다.
- onBind() 함수의 반환 값을 service 매개변수로 받은 뒤, IBinder 인터페이스를 구현했던 타입으로 형변환해서 사용한다. => 매개변수 타입이 IBinder 인터페이스인 경우, 이 인테페이스를 구현한 타입들을 매개변수로 받아들일 수 있지만, 인스턴스에 딱 맞는 타입으로 형변환 해주지 않으면 해당 타입의 멤버를 사용할 수 없다. service 참조 변수는 IBinder 타입인데, 실제 인스턴스는 MyBinder 타입임.
9. 필요할 때 Binder 객체의 함수를 호출해서 매개변수나 반환값으로 데이터를 주고 받는다.
class MainActivity : AppCompatActivity() {
lateinit var serviceBinder: MyService.MyBinder
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// ServiceConnection 객체 생성
val connection: ServiceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
serviceBinder = service as MyService.MyBinder
}
override fun onServiceDisconnected(name: ComponentName?) {
TODO("Not yet implemented")
}
}
// 서비스 실행
val intent = Intent(this, MyService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
serviceBinder.funA(10)
}
}