从基础概念到高级用法,从单向通信到多客户端管理,从内存泄漏到完整解决方案
Messenger 是 Android 提供的一种轻量级跨进程通信(IPC)方式,基于 Binder 实现。
相同点:最终跨进程传递的数据都是 Bundle,都受 Binder 1MB 限制,都必须实现 Parcelable。
class MessengerService : Service() {
private val handler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
val name = msg.data.getString("name")
// 处理消息...
}
}
private val messenger = Messenger(handler)
override fun onBind(intent: Intent): IBinder = messenger.binder
}
记得在 AndroidManifest.xml 中声明 Service,如需跨应用可设置 exported="true"。
class MainActivity : AppCompatActivity() {
private var serviceMessenger: Messenger? = null
private val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
serviceMessenger = Messenger(service)
val msg = Message.obtain().apply {
data = Bundle().apply { putString("name", "张三") }
}
serviceMessenger?.send(msg)
}
override fun onServiceDisconnected(name: ComponentName?) { serviceMessenger = null }
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val intent = Intent(this, MessengerService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
override fun onDestroy() {
super.onDestroy()
unbindService(connection)
}
}
要让服务端也能给客户端发消息,客户端需要把自己的 Messenger 通过 msg.replyTo告诉服务端。
private val replyHandler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
val reply = msg.data.getString("reply")
// 显示/处理回复
}
}
private val clientMessenger = Messenger(replyHandler)
发送消息时设置 replyTo:
val msg = Message.obtain().apply {
data = Bundle().apply { putString("name", "张三") }
replyTo = clientMessenger // 把自己的 Messenger 传过去
}
serviceMessenger?.send(msg)
override fun handleMessage(msg: Message) {
val replyMessenger = msg.replyTo
val replyMsg = Message.obtain().apply {
data = Bundle().apply { putString("reply", "收到") }
}
replyMessenger?.send(replyMsg)
}
服务端维护一个 Map<String, Messenger>,每个客户端在连接后先"注册",把自己的名字和 Messenger 告诉服务端,之后可实现客户端之间的消息转发。
private val clients = mutableMapOf<String, Messenger>()
// 处理注册
MessengerConstant.MSG_REGISTER -> {
val clientMessenger = msg.replyTo
val clientName = msg.data.getString("client_name")
if (clientMessenger != null && clientName != null) {
clients[clientName] = clientMessenger
// 回复注册成功
}
}
// 处理转发
MessengerConstant.MSG_SEND_ANOTHER -> {
val target = msg.data.getString("target")
val message = msg.data.getString("msg")
val messenger = clients[target] ?: return
messenger.send(Message.obtain().apply {
data = Bundle().apply { putString("msg", message) }
})
}
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
serviceMessenger = Messenger(service)
val msg = Message.obtain().apply {
what = MSG_REGISTER
data = Bundle().apply { putString("client_name", "MainActivity") }
replyTo = clientMessenger // 传自己的 Messenger
}
serviceMessenger?.send(msg)
}
从 Service 到 Activity 存在一条强引用链:
Service 的 clients Map (强引用)
→ Messenger (内部持有)
→ Handler (匿名内部类隐式持有)
→ Activity 实例
override fun onDestroy() {
// 1. 清空 Handler 所有消息,防止积压
handler.removeCallbacksAndMessages(null)
// 2. 通知 Service 移除自己
messengerService?.send(Message.obtain().apply {
what = MSG_UNREGISTER
data = Bundle().apply { putString("client_name", MY_NAME) }
})
// 3. 解绑
if (isBound) {
unbindService(messengerConnection)
isBound = false
}
super.onDestroy()
}
MSG_UNREGISTER -> {
val name = msg.data.getString("client_name")
clients.remove(name)
}
try {
messenger.send(msg)
} catch (e: Exception) {
clients.remove(target) // 发送失败时清理失效客户端
}
使用 弱引用(WeakReference)来观察 Activity 是否被回收。
companion object {
var weakActivity: WeakReference<SecondActivity>? = null
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
weakActivity = WeakReference(this)
}
// 在需要检查的地方
Log.d("GC_Check", "Activity是否存活? ${SecondActivity.weakActivity?.get() != null}")
| 特性 | Messenger | AIDL |
|---|---|---|
| 接口定义 | 无需 AIDL 文件,纯 Java/Kotlin | 需要编写 .aidl 文件 |
| 线程模型 | 服务端 Handler 串行处理消息 | Binder 线程池并发处理 |
| 双向通信 | 通过 replyTo 天然支持 | 需定义回调接口 |
| 多客户端管理 | 手动维护 Map | 可配合 RemoteCallbackList |
| 适用场景 | 简单消息收发、轻量级推送 | 多方法、高并发、强类型接口 |
| 数据限制 | < 1MB(Binder 限制) | < 1MB(Binder 限制) |
Messenger 足够胜任大多数普通 IPC 场景;当业务复杂、方法众多或需要并发时,才需要用 AIDL。
始终成对出现:register 和 unregister 必须配对,避免内存泄漏
销毁时清空消息:handler.removeCallbacksAndMessages(null) 防止积压
服务端容错:send() 时 try-catch,清理失效客户端
使用弱引用或 Application Context避免 UI 上下文泄漏(但彻底注销才是根本)
不同应用通信时:指定 Service 的包名,并注意权限控制
大数据勿用 Messenger:超大文件应使用文件共享或 ContentProvider
你可以用 Messenger 实现一个稳定、安全、不泄漏的跨进程通信系统。