使用AIDL实现多进程Service的流程(使用XMPP Service为例)

所有涉及到包名的地方 全部应该要 一致(包括aidl文件和java文件),最终实现 remote XMPPService

包名假定为: xyz.jimbray.xmpp

  • 编写 AIDL 相关文件(包括自定义类型数据java)

    1. 新建 IXMPPServiceInterface.aidl

      package xyz.jimbray.xmpp;
      
      import xyz.jimbray.xmpp.IXMPPReceiveListenerCallback;
      
      interface IXMPPServiceInterface {
         void registerXMPPListenerCallback(IXMPPReceiveListenerCallback listener);
         void unregisterXMPPListenerCallback(IXMPPReceiveListenerCallback listener);
      }
      

      可以看到上面包含了 一个自定义类型,看样子应该是个接口,不是普通的数据类,但是Java普通的interface类在AIDL是不能用的,所以还是要新建一个专门的接口AIDL类

    2. 新建 IXMPPReceiveListenerCallback.aidl

      package xyz.jimbray.xmpp
      
      import xyz.jimbray.xmpp.XMPPMessageBase;
      
      interface IXMPPReceiveListenerCallback {
          void OnXMPPMessageReceived(intout XMPPMessageBase messageBase);
      }
      

      这里有几个知识点

      • 自定义数据类型的使用

        XMPPMessageBase 是一个数据类,必须要实现序列化Parcelable接口

        XMPPMessageBase.java 文件 必须在同一个包名同一个包名同一个包名地址下生成,除了使用AS自动生成的Parcelable代码外,还需要另外定义一个 函数(在AIDL过程中会调用):

        public void readFromParcel(Parcel in) {
                string = in.readString();
        }
        

        同时还要新建一个 XMPPMessageBase.aidl 文件,与java文件同一个包名,文件名也是相同的

        package xyz.jimbray.xmpp;
        
        parcelable XMPPMessageBase;
        

        并且在使用 这个自定义类型数据的时候,aidl文件必须要**手动、显式地进行导入操作 **import

        看 IXMPPReceiveListenerCallback.aidl 文件的 第3行!

      • 数据的 流向设置

        在 AIDL 文件中,所有非Java基本类型的参数必须要加上 in、out、inout标记以表明参数流向

        • in : 表示参数数据只能从客户端传递到服务端,基本类型默认只支持in 流向
        • out: 表示参数数据只能从服务端传递到客户端。即:如果服务端修改了参数对象的值,那么客户端的值也会变化,但是服务端无法读取到客户端的值。
        • inout: 表示参数可以双向传递。

      到目前为止,我们写了 一共4个文件

      1. IXMPPServiceInterface.aidl
      2. IXMPPReceiveListenerCallback.aidl
      3. XMPPMessageBase.aidl
      4. XMPPMessageBase.java
  • 编写 服务端 java 代码

    1. 新建 XMPPService.java (只写关键代码)

      class XMPPService extends Service {
          
          // RemoteCallback
          final RemoteCallbackList mXMPPReceiveListenerCallbacks = new RemoteCallbackList<>();
          
          // Binder 
          private final IXMPPServiceInterface.Stub mXMPPBinder = new IXMPPServiceInterface.Stub() {
              @Override
              public void registerXMPPListenerCallback(IXMPPReceiveListenerCallback listener) {
                  // 客户端注册 callback
                  if(listener != null) {
                      mXMPPReceiveListenerCallbacks.register(listener);
                  }
              }
              
              public void unregisterXMPPListenerCallback(IXMPPReceiveListenerCallback listener) {
                  // 客户端取消注册
                  if(listener != null) {
                      mXMPPReceiveListenerCallbacks.unregister(listener);
                  }
              }
          };
          
          @Override
          public IBinder onBind(Intent intent) {
              return mXMPPBinder;
          }
          
          /**
          * XMPP 的接收消息函数
          * 收到消息之后要callback给客户端
          **/
          @Override
          public void newIncomingMessage(EntityBareJid from, Message message, Chat chat) {
              // 通过 Message 的消息,构造一个自定义的 XMPPMessageBase 数据类
              // 然后逐个通知 各客户端
              final int clientsSize = mXMPPReceiveListenerCallbacks.beginBroadcast();
              for (int i = 0; i < clientsSize; i++) {
                  try {
                      mXMPPReceiveListenerCallbacks.getBroadcastItem(i).onXMPPMessageReceived(xmppMessageBase);
                  } catch (RemoteException e) {
                      
                  }
              }
          }
          
      }
      

      到这里,服务端就完成了。

    2. 编写客户端 java 代码

      如果是不同的app,需要将AIDL相关文件原封不动地复制到新的App对应的目录中,如果是同一个App的话就不需要了。

      MainActivity.java (只写关键代码)

      private IXMPPServiceInterface mBinder;
      
      
      // 绑定服务
      bindService(Intent(this, XMPPService.class), new ServiceConnection() {
                  @Override
                  public void onServiceConnected(ComponentName name, IBinder service) {
                      mBinder = IXMPPServiceInterface.Stub.asInterface(service);
                     // 写在你应该 注册监听器的地方 mBinder.registerXMPPListenerCallback(localXMPPReceiveListenerCallback)
                  }
      
                  @Override
                  public void onServiceDisconnected(ComponentName name) {
                   // 卸载unBind Service之前即可   mBinder.unregisterXMPPListenerCallback(localXMPPReceiveListenerCallback)
                     mBinder = null;
                  }
              }, BIND_AUTO_CREATE);
      
      
      // 定义 本地的 callback 实例
      private IXMPPReceiveListenerCallback localXMPPReceiveListenerCallback = new IXMPPReceiveListenerCallback.Stub() {
              @Override
              public void onXMPPMessageReceived(XMPPMessageBase messageBase) throws RemoteException {
                  // XMPP 消息接收(从remote XMPPService 远道而来)
                  if (messageBase != null) {
                      // 消息处理
                  }
      
              }
          };
      

      到这里,一个ADIL流程就走完了。

    而且还顺便做了一个 Remote Service 的实现。

    当然了,要作为一个remote Service ,还需要进行 AndroidMenifest.xml 的配置

    
    

已发布至 我说的这句话是谎话

你可能感兴趣的:(使用AIDL实现多进程Service的流程(使用XMPP Service为例))