Messenger, AIDL 실습을 해보자

두리두두·2024년 6월 1일
0

Android

목록 보기
23/25
post-thumbnail
  • 서비스 컴포넌트 연습을 하다가, 바인더를 넘어,, 메신저, AIDL을 통해 컴포넌트 간 통신하는 것을 실습해보았다.
  • 책에서 빠르게 넘어갔던 개념들을 하나하나 파헤져보자.

🛎 Messenger 실습

[1] Message

  • 메시지 클래스는 다양한 컴포넌트, 프로세스 간 통신을 위해 쓰인다.
  • 주요 메소드는 아래와 같다.

    Message 메소드

    • obtain() : 메시지를 풀에서 가져오거나 새로운 메시지를 생성합니다.
    • sendToTarget() : 메시지를 해당 메시지가 속한 Handler의 대상으로 보냅니다.
    • setData(), setDataInt(), setDataLong() : 메시지에 데이터를 추가합니다.
    • arg1, arg2, obj : 메시지에 대한 추가적인 정보를 설정하거나 가져옵니다.

[2] Messenger

  • 메신저란, 안드로이드에서 프로세스 간 통신을 할 때 사용되는 클래스
  • Messenger는 주로 서비스 컴포넌트 간의 통신이나 프로세스 간의 통신에 사용된다. 예를 들어, 클라이언트 앱에서 서비스에 명령을 보내거나, 백그라운드 서비스에서 메인 액티비티로 데이터를 전송하는 데 사용될 수 있다.
  • 명령을 하거나, 데이터를 주고받거나 인 것이다.

🚗 메신저 객체를 생성하는 두 가지 경우

1. 액티비티에서 IBinder를 넘겨주는 경우

  • 이 경우, 액티비티가 서비스와 바인딩되고 서비스로부터 IBinder를 받아와 Messenger를 생성
  • 이렇게 생성된 Messenger는 서비스에게 메시지를 보낼 때 사용됩니다. 액티비티에서 생성된 Messenger를 통해 메시지를 보내면, 해당 메시지는 서비스의 Handler에 도달하게 된다.
    2. 서비스에서 핸들러를 넘겨주는 경우
  • 이 경우, 서비스의 Handler를 사용하여 받은 메시지를 처리
  • 클라이언트 앱에서 생성된 Messenger가 서비스의 핸들러를 통해 메시지를 전달합니다. 이 핸들러는 서비스에서 메시지를 수신하고 처리하는 역할을 한다.
  • 기본 메소드로는 send(Message), getBinder() 등이 있다.

실습

1) MyService.kt

class MyService : Service() {
    // 난 메신저를 쓸거다
    private lateinit var messenger: Messenger

    override fun onCreate() {
        super.onCreate()
        // 메신저를 만들때엔 메신저 객체에 핸들러를 매개변수로 넘겨줘야한다.
        messenger = Messenger(IncomingHandler())
    }
    override fun onBind(intent: Intent): IBinder {
        // onBind에서 메신저의 바인더를 리턴해줌
        return messenger.binder
    }

    private inner class IncomingHandler: Handler(){
        // 핸들러는 말그대로,, 어떻게 핸들할 것이다를 담고 있다
        // 메세지 객체는 핸들러를 통해 메시지 큐에 전달된다.
        override fun handleMessage(msg: Message) {
            when (msg.what){
                MSG_HELLO -> {
                    // 처리할 내용
                    showToast("hello from client~")
                }

                else -> super.handleMessage(msg)
            }

        }

    }
    companion object {
        const val MSG_HELLO = 1
    }

    // 토스트 메시지를 띄우는 함수
    private fun showToast(message: String) {
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
    }
}

2) MainActivity.kt

  • onCreate에서 bindService로 서비스를 연결해준 후, 만들어진 Messenger(onServiceConnected)에 메세지를 send해주는 것이 핵심
  • 어케 핸들할지 담은 binder를 반환받아 messenger 객체를 만들어준다.
class MainActivity : AppCompatActivity() {
    private var messenger : Messenger? = null
    private var bound = false

    // 서비스컴포넌트 쓸 것이니 서비스 커넥션 생성
    private val serviceConnection = object: ServiceConnection{
        override fun onServiceConnected(p0: ComponentName?, p1: IBinder?) {
            // 서비스와 바인딩되는 메신저 객체 생성
            // 서비스 컴포넌트의 onBind에서 반환한 messenger.bind를 IBinder형태로 받아와서 넣어줌
            messenger = Messenger(p1)
            bound = true
        }

        override fun onServiceDisconnected(p0: ComponentName?) {
            messenger = null
            bound = false
        }
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val intent = Intent(this, MyService::class.java)
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)

        val btnSend = findViewById<Button>(R.id.btnSend)
        btnSend.setOnClickListener {
            sendMessageToService()
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        if (bound){
            unbindService(serviceConnection)
            bound = false
        }
    }

    private fun sendMessageToService(){
        if (!bound) return
        // 메시지를 얻기 위해 사용. 메세지풀에서 가져옴
        val message = Message.obtain(null, MyService.MSG_HELLO, 0,0)
        try{
            // 메신저 클래스의 기본 메소드. 메세지 객체를 넣어서 보내면 메신저의 handleMessage로 넘어감
            messenger?.send(message)
        }catch(e:RemoteException){
            e.printStackTrace()
        }
    }
}
  • 참 구린 결과 gif.. 하지만 버튼을 누르면 서비스를 호출하고 메신저를 만들어 핸들러가 호출되어 토스트가 뜨는 것을 볼 수 있다~

🛎 AIDL 실습

[1] aidl 파일 생성

  • 확장자가 aidl인 인터페이스 파일을 만든다. 이 때 안드로이드 스튜디오 > New > File > AIDL 을 선택해서 만드시길... 셀프로 파일 만들었다가 인식이 안되어 한시간동안 진행을 못했다.
// IMyAidlInterface.aidl
package com.example.ch15_aidl;

// Declare any non-default types here with import statements

interface IMyAidlInterface {
    void showToastMessage(String message);
}

[2] MyAIDLService.kt

  • 메신저보다 간단하다. onBind()에서 binder를 리턴해주면 되는데, 그 binder는 IMyAidlInterface.Stub()를 하면 해당 AIDL 인터페이스의 Binder 객체가 반환된다. 이 Binder 객체를 클라이언트와 서비스 간의 통신을 위한 인터페이스로 사용할 수 있는 것.
class MyService : Service() {

    override fun onBind(intent: Intent): IBinder {
        return binder
    }
	// binder 객체 생성
    private val binder = object : IMyAidlInterface.Stub(){
        override fun showToastMessage(message : String){
        // Display a toast message
            message?.let {
                Toast.makeText(applicationContext, it, Toast.LENGTH_SHORT).show()
            }
        }
    }
}

[3] MainActivity.kt

  • 다른 기법과 마찬가지로 bindService()로 서비스와 바인딩한다.
  • ServiceConnection에서 IMyAidlInterface.Stub.asInterface(service)로 바인딩해준다.
  • 그리고 사용할 일이 있을 때 (onClikck 이벤트 등) 인터페이스에 정의되어있는 메소드를 호출한다.
class MainActivity : AppCompatActivity() {
    private var service: IMyAidlInterface? = null
    private var bound = false

    private val connection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            this@MainActivity.service = IMyAidlInterface.Stub.asInterface(service)
            bound = true
        }

        override fun onServiceDisconnected(name: ComponentName?) {
            service = null
            bound = false
        }
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val intent = Intent(this, MyService::class.java)
        bindService(intent, connection, Context.BIND_AUTO_CREATE)

        val btnSend = findViewById<Button>(R.id.btnSend)
        btnSend.setOnClickListener {
            sendMessageToService()
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        if (bound) {
            unbindService(connection)
            bound = false
        }
    }

    // Method to send message to the service and display toast
    private fun sendMessageToService() {
        val message = "AIDL service to Client!"
        service?.showToastMessage(message)
    }
}
  • 실습 결과는 messenger와 동일해서 패스,,

🛎 정리

  • 정리하며 챗지피티에게 물어본 binder, messenger, AIDL 방식의 차이점이다.
profile
야금야금 앱 개발자

0개의 댓글