바인딩 서비스

k_hyun·2023년 3월 9일
0

바인딩 서비스

백그라운드 작업은 필요하지만 액티비티와 데이터를 주고받을 일이 없는 등 서로 관련이 없다면 startService() 함수로 서비스를 실행하면 된다.

bindService()는 서비스와 액티비티가 상호작용 해야 할 때 호출하는 함수이다.
bind는 서비스가 실행되면서 자신을 실행한 곳에 객체를 바인딩, 전달한다는 의미이다.

// 서비스 코드

class MyBinder : Binder() {
	fun funA(arg: Int) {}
	...
}

override fun onBind(intent: Intent): IBinder? {
	return MyBinder()
}

bindService() 함수로 서비스를 실행하면 onBind()가 실행되는데, 이 함수에는 반환 타입이 선언되어 있다.
IBinder 인터페이스를 구현한 객체를 전달한다.

// 액티비티 코드

val connection: ServiceConnection = object : ServiceConnection {
	override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
    	serviceBinder = service as MyService.MyBinder
	}
    override fun onServiceDisconnected(name: ComponentName>) {}
}

...

// 서비스에서 바인딩한 객체 함수 호출
serviceBinder.funA(10)

onServiceConnected 의 두 번째 매개변수가 서비스에서 전달한 객체이다.

메신저 바인딩

bindServce() 함수로 서비스를 실행한 곳에는 IBinder를 구현한 객체를 바인딩한다.

API에서 제공하는 Messenger 객체를 바인딩하는 방법도 존재한다.

// 서비스 코드
class MyService : Service() {
	lateinit var messenger: Messenger
    internal class IncompingHandler(
    context: context, private val applicationContext: Context = context.applicationContext)
    : Handler(Loper.getMainLooper()) {
    override fun HandleMessage(msg: Message) {
    	when (msg.what) {
        	10 -> Toast.makeText(applicationContext, "${msg.obj}", Toast.LENGTH_SHORT).show()
            20 -> Toast.makeText(applicationContext, "${msg.obj}", Toast.LENGTH_SHORT).show()
            else -> super.handleMessage(msg)
            }
        }
    }
    override fun onBind(intent: Intent): IBinder? {
    	messenger = Messenger(IncomingHandler(this))
        return messenger.binder
    }
}       

handleMessage() 함수는 외부에서 서비스에 데이터를 전달할 때 자동으로 호출된다.
Messenger 객체의 binder 속성을 onBind() 함수의 결괏값으로 반환해 준다.

// 액티비티 코드
class MainActivity : AppCompatActivity() {
	lateinit var messenger: Messenger
    override fun onCreate(savedInstanceState: Bundle?) {
    	super.onCreate(savedInstanceState)
        ...
        val intent = Intent(this, MyService::class.java)
        bindService(intent, connection, Context.BIND_AUTO_CREATE)
    }
    
    val connection: ServiceConnection = object : ServiceConnection {
    	override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
        	messenger = Messenger(service)
        }
        override fun onServiceDisconnected(name: ComponentName?) {}
    }
}

프로세스 간 통신에서 주고받는 데이터는 Parcelabel이나 Bundle 타입이어야 한다.
따라서 데이터를 Bundle에 담고 다시 Message 객체에 담아서 전달한다.

val bundle = Bundle()
bundle.putString("data1", "hello")
bundle.putInt("data2", 10)

val msg = Message()
msg.what = 10
msg.obj = bundle
messenger.send(msg)

AIDL 통신

AIDL (Android Interface Definition Language)은 두 프로세스 사이에 데이터를 주고받는 프로세스 간 통신을 구현할 때 사용하는 기법이다.
기본적으로 안드로이드는 데이터를 시스템에 전달한 후 시스템이 다른 프로세스에 전달해준다.
이러한 절차에서 마샬링과정을 거쳐야 하는데, AIDL을 이용하면 이러한 작업을 대신 처리해주므로 편리하다.

MyAIDLInterface.aidl을 작성한다. 자바로 작성한 인터페이스이다.

package com.example.test_aidl;

interface MyAIDLInterface {
	void funA(String data);
    int funB();
}

AIDL 파일에 선언된 함수를 구현해 실제 작업을 처리하는 내용을 작성하는 곳은 서비스이다.

// 서비스 컴포넌트 구현
class MyAIDLService : Service() {
	override fun onBind(intent: Intent): IBinder {
    	return object : MyAIDLInterface.Stub() {
        	override fun funA(data: String?) {}
            override fun funB(): Int {return 10}
        }
    }
}

AIDL 파일을 구현한 객체가 아니라 프로세스 간 통신을 대행해 주는 Stub을 전달한다.

// 외부 앱의 서비스 실행
class MainActivity : AppCompatActivity() {
	...
	val connection: ServiceConnection = object : ServiceConnection {
    	override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
        	aidlService = MyAIDLInterface.Stub.asInterface(service)
        }
        override fun onServiceDisconnected(name: ComponentName?) {}
    }
    ...
    aidlService.funA("hello")
}

0개의 댓글