-
客户端 → 服务端:请求数据
-
服务端 → 客户端:返回结果
-
服务端 → 客户端:通过回调接口主动通知(真正的双向通信)
🧩 一、AIDL 文件结构
代码
aidl/
├── IRemoteService.aidl
└── IRemoteCallback.aidl
🧭 二、定义回调接口(客户端实现,服务端调用)
IRemoteCallback.aidl
aidl
package com.demo.ipc;
interface IRemoteCallback {
void onResult(int code, String message);
}
🧭 三、定义服务端接口(客户端调用,服务端实现)
IRemoteService.aidl
aidl
package com.demo.ipc;
import com.demo.ipc.IRemoteCallback;
interface IRemoteService {
// 普通请求:客户端 → 服务端
int add(int a, int b);
// 注册回调:客户端把 callback 传给服务端
void registerCallback(IRemoteCallback callback);
// 注销回调
void unregisterCallback(IRemoteCallback callback);
}
🧩 四、服务端实现(Service + Binder)
RemoteService.kt
kotlin
class RemoteService : Service() {
private val callbacks = RemoteCallbackList<IRemoteCallback>()
private val binder = object : IRemoteService.Stub() {
override fun add(a: Int, b: Int): Int {
return a + b
}
override fun registerCallback(callback: IRemoteCallback?) {
if (callback != null) {
callbacks.register(callback)
}
}
override fun unregisterCallback(callback: IRemoteCallback?) {
if (callback != null) {
callbacks.unregister(callback)
}
}
}
override fun onBind(intent: Intent?): IBinder = binder
// 服务端主动回调客户端
fun notifyClients() {
val count = callbacks.beginBroadcast()
for (i in 0 until count) {
callbacks.getBroadcastItem(i).onResult(200, "服务端主动推送消息")
}
callbacks.finishBroadcast()
}
}
🧠 服务端关键点说明
-
RemoteCallbackList用于管理跨进程回调(自动处理死亡代理) -
registerCallback()/unregisterCallback()用于客户端注册监听 -
notifyClients()是服务端主动推送消息给客户端的地方
你可以在定时器、网络回调、业务事件中调用它。
🧩 五、客户端实现(绑定服务 + 注册回调)
ClientActivity.kt
kotlin
class ClientActivity : AppCompatActivity() {
private var remoteService: IRemoteService? = null
private val callback = object : IRemoteCallback.Stub() {
override fun onResult(code: Int, message: String?) {
Log.d("Client", "收到服务端回调: code=$code, msg=$message")
}
}
private val conn = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
remoteService = IRemoteService.Stub.asInterface(service)
// 注册回调
remoteService?.registerCallback(callback)
// 调用服务端方法
val result = remoteService?.add(3, 5)
Log.d("Client", "add(3,5) = $result")
}
override fun onServiceDisconnected(name: ComponentName?) {
remoteService = null
}
}
override fun onStart() {
super.onStart()
val intent = Intent()
intent.setClassName("com.demo.ipcserver", "com.demo.ipc.RemoteService")
bindService(intent, conn, BIND_AUTO_CREATE)
}
override fun onStop() {
super.onStop()
remoteService?.unregisterCallback(callback)
unbindService(conn)
}
}
🧠 客户端关键点说明
-
IRemoteCallback.Stub()是客户端实现的回调接口 -
registerCallback()把回调传给服务端 - 服务端调用
onResult()时,客户端会立即收到消息 -
add()是普通同步 IPC 调用
🔥 六、Demo 的双向通信流程图
代码
客户端 ----------------------> 服务端
add(a,b)
客户端 ----------------------> 服务端
registerCallback(callback)
服务端 ----------------------> 客户端
callback.onResult(...)
这是典型的:
- 请求 → 响应
- 服务端主动推送
双向通信完整闭环。
🧩 七、AIDL 的 in / out / inout 关键字
-
in:只读输入 -
out:只写输出(客户端传入的对象会被服务端“填充”) -
inout:读 + 写(客户端传入对象 → 服务端修改 → 回传)
你不需要额外定义一个“返回模型”,除非你想让输入和输出完全不同。
🧩 为什么 90% 场景用 in?
因为:
- 大多数参数只是输入
-
in性能最好(只序列化一次) - 逻辑最简单
- 不需要回传修改后的对象
例如:
aidl
void updateUser(in User user);
服务端修改 user 不会回传给客户端。
🧠 那么如果我需要返回数据怎么办?
你有两种选择:
✔ 方案 1:定义一个返回值(最常用)
例如:
aidl
User getUser(int id);
这是最清晰、最常见的方式。
客户端:
kotlin
val user = service.getUser(1)
✔ 方案 2:使用 out 或 inout(复用同一个对象)
例如:
aidl
void getUser(out User user);
客户端:
kotlin
User user = new User(); // 空对象
service.getUser(user);
// user 现在被服务端填充了
服务端:
java
void getUser(User user) {
user.id = 1;
user.name = "Tom";
}
注意:客户端传入的 user 对象会被服务端“写回”数据。
🔥 重点:out 和 inout 是否可以复用客户端传入的对象?
答案是:
可以,而且这是它们的设计目的。
✔ out:只回传,不读取输入
客户端传入的对象内容会被忽略,但对象本身会被用来“承载返回值”。
✔ inout:既读取输入,也回传修改后的内容
客户端传入的对象 → 服务端修改 → 回传给客户端。
🧭 什么时候用 out / inout?
| 场景 | 推荐关键字 |
|---|---|
| 只需要返回数据 | out |
| 需要传入对象并让服务端修改后回传 | inout |
| 只需要传入,不需要回传 |
in(默认) |
🎯 最终总结(非常关键)
✔ 你不需要额外定义一个“返回模型”
使用 out 或 inout 时:
- 客户端传入的对象本身就是“返回容器”
- 服务端直接写入这个对象
- Binder 会把修改后的对象序列化回客户端
✔ 但实际工程中,推荐使用“返回值”方式
因为:
- 更清晰
- 更符合直觉
- 更容易维护
- 更少序列化开销
例如:
aidl
User getUser(int id);