最近有个需求,用到了AIDL来进行跨进程通信,关于AIDL,我们常规的操作是客户端向服务端发送请求,这很简单,只需要在Stub上调用定义的方法即可,顶多需要执行方法的返回值。
但是坑爹的需求总是那么多,例如我需要反向操作,服务器端向客户端发送数据。整个Binder的模型有点像网络的DNS模型,既然能连通,那应该是可以反着走的。
回想一下观察者模式,被观察者持有观察者的一个接口回调,当被观察者数据变化时,通过该接口通知外部的观察者数据的变化情况,主体思路就是这样。
注意的内容是什么呢?
1、由于我们是进行了跨进程的操作,定义的回调接口理论上不属于AIDL默认支持的数据类型,所以要新建一个AIDL文件
2、原先的Stub类需要注册这个回调接口
3、关注 RemoteCallbackList 这个类,它是专门用于删除跨进程listener的接口,它是一个泛型,支持管理任意的AIDL接口
上核心代码:
1、新建listener的AIDL
interface IOnWebSocketListener {
void onSocketConnected();
void onReceiveServerMessage(in CMDEntity aidlCMDEntity);
void onSocketClose();
void onSocketError();
}
2、原有的AIDL注册listener
import com.ideacode.test.IOnWebSocketListener;
interface IWebSocketAidlInterface {
void registListener(IOnWebSocketListener listener);
void unregistListener(IOnWebSocketListener listener);
}
3、客户端要做的事情
private IWebSocketAidlInterface webSocketAidlInterface;
IOnWebSocketListener listener = new IOnWebSocketListener.Stub() {
@Override
public void onSocketConnected() throws RemoteException {
Logger.e("连接成功");
}
@Override
public void onReceiveServerMessage(CMDEntity aidlCMDEntity) throws RemoteException {
Logger.e("收到消息:" + aidlCMDEntity.getMessage());
}
@Override
public void onSocketClose() throws RemoteException {
Logger.e("连接关闭");
}
@Override
public void onSocketError() throws RemoteException {
Logger.e("连接异常");
}
};
ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
webSocketAidlInterface = IWebSocketAidlInterface.Stub.asInterface(iBinder);
try {
webSocketAidlInterface.registListener(listener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
webSocketAidlInterface = null;
}
};
@Override
protected void onDestroy() {
super.onDestroy();
if (serviceConnection != null && webSocketAidlInterface.asBinder().isBinderAlive()) {
try {
webSocketAidlInterface.unregistListener(listener);
} catch (RemoteException e) {
e.printStackTrace();
}
unbindService(serviceConnection);
}
}
4、服务端要做的事情
private RemoteCallbackList<IOnWebSocketListener> mListener = new RemoteCallbackList<>();
IWebSocketAidlInterface.Stub mBinder = new IWebSocketAidlInterface.Stub() {
@Override
public void registListener(IOnWebSocketListener listener) throws RemoteException {
mListener.register(listener);
WebSocketManager webSocketManager = WebSocketManager.getInstance();
webSocketManager.registCallback(mListener);
}
@Override
public void unregistListener(IOnWebSocketListener listener) throws RemoteException {
mListener.unregister(listener);
WebSocketManager webSocketManager = WebSocketManager.getInstance();
webSocketManager.unregistCallback(mListener);
}
};
5、在需要的位置进行listener的响应
private RemoteCallbackList<IOnWebSocketListener> callbackList;
@Override
public void onOpen(ServerHandshake handshakedata) {
//连接成功
Logger.i("websoeket opened connection");
int n = callbackList.beginBroadcast();
for (int i = 0; i < n; i++) {
IOnWebSocketListener listener = callbackList.getBroadcastItem(i);
if (listener != null) {
try {
listener.onSocketConnected();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
callbackList.finishBroadcast();
}
注意的地方:
1、RemoteCallbackList这个东西并不是一个List,所以不能进行foreach遍历
2、beginBroadcast和finishBroadcast要成堆出现,哪怕是要获取RemoteCallbackList中的元素个数。
这样客户端就能收到服务器端回调过来的消息啦,实测通过,比我之前用的方案更清晰,很好很好!!!
网友评论