IPC机制之了解Messenger
Messenger翻译“信使”
在message中放入要跨进程的数据,使用Messenger发送则可以实现跨进程通讯,系统进行了封装,就不需要自己实现写aidl了。
实现方式
与传统的aidl传输相同,也是分为客户端与服务端进行通信。
服务端
服务端主要创建service,同时,以Handler创建Messenger,在service中的onBinder中返回Messenger中的Binder。
代码附上:
package com.example.service
import android.app.Service
import android.content.Intent
import android.os.*
import android.util.Log
class MessengerService : Service() {
private class MessengerHandler : Handler() {
override fun handleMessage(msg: Message) {
when (msg.what) {
1 -> {
Log.e(TAG, "handleMessage:收到信息 :"+msg.data.getString("client_send"))
val clientMessenger = msg.replyTo
val message = Message.obtain(null, 1)
val bundle = Bundle()
bundle.putString("service_send", "来啦!!!")
message.data = bundle
clientMessenger.send(message)
}
2 -> {
}
else -> super.handleMessage(msg)
}
}
}
private val messenger = Messenger(MessengerHandler())
override fun onBind(intent: Intent): IBinder? {
return messenger.binder
}
companion object {
private const val TAG = "MessengerService"
}
}
不用多说,service必须在AndroidManifest.xml中声明:
<service
android:name=".MessengerService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.service.MessengerService"/>
</intent-filter>
</service>
注意:action必须声明,后续跨进程通信启动服务要用到, android:enabled=“true”
android:exported="true"也要有。
服务端部署完毕,安装就行,不启动依旧可以生效。
客户端:
客户端主要启动服务,将自己的Messenger ,放入发送的message的replyTo 中,这样,服务器那边就可以有一个对应的Messenger,发送信息回来,这样,就可以来回通信了。实现较为简单。
package com.example.client
import android.annotation.SuppressLint
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.*
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
private val TAG = "MessengerClient"
lateinit var serviceMessenger: Messenger
var serviceConnection: ServiceConnection = object : ServiceConnection {
override fun onServiceDisconnected(name: ComponentName?) {
}
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
serviceMessenger = Messenger(service)
}
}
var stringBuffer: StringBuffer = StringBuffer()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val intent = Intent()
intent.setPackage("com.example.service")
intent.action = "com.example.service.MessengerService"
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
send_message.setOnClickListener {
val message = Message.obtain(null, 1)
message.replyTo = clientMessenger
val bundle = Bundle()
bundle.putString("client_send", "来啦!老弟!")
message.data = bundle
serviceMessenger.send(message)
stringBuffer.append("Client:来啦!老弟!\n")
all_message.text=stringBuffer
}
}
private val clientMessenger: Messenger = Messenger(@SuppressLint("HandlerLeak")
object : Handler() {
override fun handleMessage(msg: Message) {
Log.e(TAG, "handleMessage:收到信息 :" + msg.data.getString("service_send"))
stringBuffer.append("Service:${msg.data.getString("service_send")}\n")
all_message.text=stringBuffer
super.handleMessage(msg)
}
})
override fun onDestroy() {
unbindService(serviceConnection)
val intent = Intent()
intent.setPackage("com.example.service")
intent.action = "com.example.service.MessengerService"
stopService(intent)
super.onDestroy()
}
}
点击客户端按钮,服务端打出日志,并且回复。效果如下:
分析
往下看,可以看到:
messenger本身是实现了parcelable接口
这两处也可以和aidl相对应;
再看看IMessage接口。
Message参数的定向TAG是in,这说明服务端对Message对象更改,客户端是不会变化的。
可以参考
IPC机制之了解AIDL(二)定向TAG in out inout的验证和结论:
结论
- Messenger本质也是AIDL,只是进行了封装,开发的时候不用再写.aidl文件。
- 在service端,Messenger处理client端的请求是单线程的,而AIDL是多线程的。使用AIDL的时候,service端每收到一个client端的请求时,就会启动一个线程(非主线程)去执行相应的操作。而Messenger,service收到的请求是放在Handler的MessageQueue里面,Handler需要绑定一个Thread,然后不断poll message执行相关操作,这个过程是同步执行的。
- 由于Messenger中send方法是的定向TAG是in,因此服务端与客户端中的数据是异步的,只是将客户端的数据发送至服务端,服务端更改后对客户端的数据并不能产生影响。只能使用客户端通过relayTo传过来的Messenger将另一个Message发送回去。实现服务端与客户端的通信。