美文网首页Android开发经验谈
关于AIDL 服务端向客户端传输数据问题

关于AIDL 服务端向客户端传输数据问题

作者: 捉影T_T900 | 来源:发表于2018-04-25 23:12 被阅读75次

    最近有个需求,用到了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中的元素个数。

    这样客户端就能收到服务器端回调过来的消息啦,实测通过,比我之前用的方案更清晰,很好很好!!!

    相关文章

      网友评论

        本文标题:关于AIDL 服务端向客户端传输数据问题

        本文链接:https://www.haomeiwen.com/subject/uvsulftx.html