真实场景:车载 HMI 不会用轮询拿车辆数据。页面打开先用拉取拿到初始值避免空白;对于车速、告警这类实时变化的数据,通过订阅注册回调,由 CarService 服务端发生变化后主动推送更新 UI。设置、配置这类很少变动的数据,使用单次拉取即可。
1、总览流程图

2、关键:Stub / Proxy 怎么「对调」
拉:问一句
bash
HMI --ICarService.Proxy--> Binder --ICarService.Stub--> CarService
getSpeed()
推:报一句(座位对调)
bash
CarService --Listener.Proxy--> Binder --Listener.Stub--> HMI
onSpeedChanged(85)
对调 = 换了一条「谁打给谁」的接口;通道仍是 Binder。
3、最小代码示意
AIDL
bash
// 推送用的「回拨接口」
interface ICarSpeedListener {
void onSpeedChanged(int speed);
}
interface ICarService {
int getSpeed();
void registerSpeedListener(ICarSpeedListener listener);
void unregisterSpeedListener(ICarSpeedListener listener);
}
Client:留下接听 Stub
bash
ICarSpeedListener.Stub speedListener = new ICarSpeedListener.Stub() {
public void onSpeedChanged(int speed) {
// 常在 Binder 线程 → 切主线程再改 UI
mainHandler.post(() -> updateSpeedUi(speed));
}
};
// 连接成功后
carService.registerSpeedListener(speedListener);
Server:当 Proxy 去打
bash
RemoteCallbackList<ICarSpeedListener> listeners = ...;
void notifySpeed(int speed) {
int n = listeners.beginBroadcast();
for (int i = 0; i < n; i++) {
listeners.getBroadcastItem(i).onSpeedChanged(speed);
// ↑ Server 调的是 Listener.Proxy
}
listeners.finishBroadcast();
}
4、总结
Service「推送」并不神秘:
Client 用 Listener.Stub 注册回拨
Server 保存后用 Listener.Proxy 反向调用
还是 Binder,只是 Stub/Proxy 角色对调
会讲这三句,回调这块就算过关了。