Android でサービスと通信する-Messenger編
  • ブロードキャストを送信する
  • LiveDataを使う
  • Messanger を使う
  • 3 部作の最後です、Messanger を使ってみます。

    アクティビティとハンドラーの定義です。

    package red.txn.service_messenger
    
    import android.content.ComponentName
    import android.content.Context
    import android.content.Intent
    import android.content.ServiceConnection
    import android.os.Bundle
    import android.os.Handler
    import android.os.IBinder
    import android.os.Looper
    import android.os.Message
    import android.os.Messenger
    import android.util.Log
    import androidx.activity.ComponentActivity
    import androidx.activity.compose.setContent
    import androidx.activity.enableEdgeToEdge
    import androidx.compose.foundation.layout.fillMaxSize
    import androidx.compose.foundation.layout.padding
    import androidx.compose.material3.Scaffold
    import androidx.compose.material3.Text
    import androidx.compose.runtime.Composable
    import androidx.compose.ui.Modifier
    import androidx.compose.ui.tooling.preview.Preview
    import red.txn.service_messenger.MainActivity.Companion.TAG
    import red.txn.service_messenger.ui.theme.ServicemessengerTheme
    
    
    
    class MainActivity : ComponentActivity() {
        companion object {
            const val TAG = "MainActivity"
        }
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            enableEdgeToEdge()
            setContent {
                ServicemessengerTheme {
                    Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
                        Greeting(
                            name = "Android",
                            modifier = Modifier.padding(innerPadding)
                        )
                    }
                }
            }
    
            // launch service
            Intent(this, MessengerService::class.java).also { intent ->
                bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
            }
        }
    
        private lateinit var messenger: Messenger
        private val serviceConnection = object : ServiceConnection {
            override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
                messenger = Messenger(service)
            }
    
            override fun onServiceDisconnected(name: ComponentName?) {
                Log.d(TAG, "onServiceDisconnected()")
            }
        }
    }
    
    class MessageHandler: Handler(Looper.getMainLooper()) {
        override fun handleMessage(msg: Message) {
            when(msg.what) {
                MESSAGE_FROM_SERVICE-> {
                    // handle the response message
                    Log.d(TAG, "received: ${msg.data.toString()}")
                }
                else -> {
                    Log.d(TAG, "received other: $msg")
                }
            }
        }
    }
    
    //***
    //*** compsable functions
    //***
    @Composable
    fun Greeting(name: String, modifier: Modifier = Modifier) {
        Text(
            text = "Hello $name!",
            modifier = modifier
        )
    }
    
    @Preview(showBackground = true)
    @Composable
    fun GreetingPreview() {
        ServicemessengerTheme {
            Greeting("Android")
        }
    }

    class Handler はサービスでも参照します。

    
    package red.txn.service_messenger
    
    import android.app.Service
    import android.content.Intent
    import android.os.Binder
    import android.os.Handler
    import android.os.IBinder
    import android.os.Looper
    import android.os.Message
    import android.os.Messenger
    import android.util.Log
    import kotlinx.coroutines.CoroutineScope
    import kotlinx.coroutines.Dispatchers
    import kotlinx.coroutines.cancel
    import kotlinx.coroutines.launch
    
    
    const val MESSAGE_FROM_SERVICE: Int = 2
    
    class MessengerService : Service() {
        companion object {
            const val TAG = "MessengerService"
        }
    
        private val messenger = Messenger(MessageHandler())
    
    
        override fun onBind(intent: Intent): IBinder {
            Log.d(TAG, "onBind()")
            Thread {
                for (i in 1..2) {
                    Thread.sleep(2000)
                    sendMessageFromService()
                    Log.d(TAG, "sendBroadcast: $i")
                }
            }.start()
            return MyBinder()
        }
    
        inner class MyBinder: Binder() {
            fun getService(): MessengerService = this@MessengerService
        }
    
        private fun sendMessageFromService() {
            val message = Message.obtain()
            message.what = MESSAGE_FROM_SERVICE
            message.data.putString("message", "Hello from MessengerService")
            //message.replyTo = messenger
            messenger.send(message)
        }
    
        override fun onDestroy() {
            super.onDestroy()
            Log.d(TAG, "onDestroy(")
        }
    }

    普通はメッセージの場合、普通は双方向通信に使うことが多いようですが、message.replyTo が空でも問題ないようです。

    ちょっと試していないのでなんともいえませんがこのサービスももしかすると、startService() 起動に書き換えることができるかもしれません。その場合は Messenger を Activity に渡す必要があるので、LiveData の時と同じようにMessenger を companion object にする必要がありそうです。