startService()와 달리 하나 이상의 클라이언트 컴포넌트 간의 통신을 구현 가능
서비스를 실행시켜 두고 필요할 때 마다 서비스의 메소드를 접근하여 통신할 수 있는 구조
Service가 Background에서 실행되고 있을 때, Activity에서 Service의 메소드를 호출/결과를 받아서 보여주는 Interaction을 해야할 경우 등에 사용된다.
Binder는 기본적으로 Process간 통신을 제공한다.
bindService 생명주기
bindService() 함수로 시작 하면 onCreate() -> onBind() 함수가 호출되면서 Running 상태가된다.
bindService() 함수로 실행된 서비스는 unbindService()로 종료
종료될 때 onUnbind() -> onDestroy() 함수가 호출된다.
Local에서 구현
Local이 아닌 경우(다른 프로세스)
Messenger와 Handler를 사용한다.
AIDL(Android Interface Definition Language)를 이용하여 서비스 구현
IPC/Binder
IPC(Inter Process Communication)
프로세스 통신, 리눅스 커널에서 Binder를 이용하여 프로세스간 메시지를 주고 받도록 구현되어 있다.
안드로이드 리눅스 커널을 기반으로 만들어져 있으므로, process는 kernel 내부의 일정 공간을 공유하여 함수를 호출하며 이를 Binder Driver가 수행
Parcel / Parcelable
Binder는 데이터를 parcel 형태로 전달하기 때문에 안드로이드에서는 parcelable 클래스를 활용
안드로이드에서는 Serializable 보다는 Parcelable을 권장
Activity생성 -> Service Connection -> Service -> Binder -> Service Connection -> (서비스가 다시 시작되면 처음부터) -> Activity
class BoundService : Service() {
private val mBinder: IBinder = MyLocalBinder()
override fun onCreate() {
super.onCreate()
}
override fun onBind(intent: Intent?): IBinder {
return mBinder
}
inner class MyLocalBinder : Binder() {
// getService가 호출되면서 myService가 실행된다.
fun getService(): BoundService {
// getService를 호출하면 this를 통해서 자신인, BoundService가 return 된다.
return this@BoundService
}
} // End of MyLocalBinder inner class
} // End of BoundService class
MainActivity
private val connection =
object : ServiceConnection {
// MyLocalBinder가 IBinder 이므로 타입캐스팅이 가능하다.
// 연결될 때 service가 IBInder가 onBind이다.
// IBinder가 MyLocalBinder 이기 때문에 (MyLocalBinder가 IBinder 타입임)
// service가 MyLocalBinder로 타입 캐스팅할 수 있다.
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
val binder = service as BoundService.MyLocalBinder
myService = BoundService()
myService = binder.getService()
isBound = true
}
override fun onServiceDisconnected(name: ComponentName?) {
isBound = false
}
}
override fun onStart() {
super.onStart()
val intent = Intent(this, BoundService::class.java)
bindService(intent, connection, BIND_AUTO_CREATE)
}
onBind 함수에서는 BoundService의 IBinder 객체를 반환함
현재 시간을 반환하는 getCurrentTime() 함수 구현. 클라이언트가 이 method를 호출하기 위해서 bind함
Inner class로 Binder의 서브클래스인 MyLocalBinder를 정의하고 이 클래스는 getService 함수에서 서비스 인터페이스를 반환해주는 역할을 한다.
private val mBinder : IBinder = MyLocalBinder()를 통해서 new로 MyLocalBinder를 생성함 타입은 IBinder타입으로 지정
MyLocalBinder는 Binder를 상속 받았고, Binder가 IBinder를 상속받았기 때문에 MyLocalBinder는 IBinder 타입을 받을 수 있다. 즉, onBind에서 return type이 IBinder 타입을 return 한다는 것은 onBind가 myBinder를 return해도 된다는 얘기가 된다.
Binder의 구현체를 보면, IBinder를 implements함.
IBinder -> Binder 임, MyLocalBinder가 Binder를 상속받는다는 것은 MyLocaBinder가 IBinder 타입이 될 수 있다는 것을 얘기함.
(구조가 조금 복잡하다...)
onStart에서 bindService를 실행한다.
이렇게 해서 BoundService에서 구현된 함수를 getService를 통해서 호출 할 수 있다.
복잡한 로직, 또는 시간이 걸리는 작업의 경우를 Service내부에서 구현하고 작업하여 줄 수 있다.