Android AIDL 初步探索

        在Android 應用開發過程中涉及到進程間通信的場景不多,但是隨着進程化開發的實現,單APP多進程的情況也越來越多。這就涉及到IPC進程間通信,而Binder 就是其中的一種,Android中很多情況 IPC 通信都是通過 Binder 實現的,其底層相對複雜,在應用層,我們可以理解Binder 就是一個Java 類,在進程間通信的 client -> service 結構中數據的傳遞是通過Binder 來實現的。而Android 爲了方便我們實現這一功能 提供了AIDL 文件   Android Interface Definition Language(安卓接口定義語言)

       要實現進程間通信我們需要創建 service 端和 client 端

1.創建AIDL 文件 

// IServiceInterface.aidl
package com.fyh.aidl;

// Declare any non-default types here with import statements

interface IServiceInterface {
    /**
     * 這邊默認生成的一個方法 可以不用管,這裏寫個getData() 方法獲取數據
     */
   String getData();
}

當創建好AIDL文件 編譯後,會自動生成一個 對應名稱的Java 接口類 

public interface IServiceInterface extends android.os.IInterface

2.創建 service 

public class AIDLService extends Service {
    public AIDLService() {
    }

    
    @Override
    
    public IBinder onBind(Intent intent) {
        return stub;
    }
    
    //這裏 Stub 是一個繼承 IBinder 的抽象類,所以 IServiceInterface.Stub 是我們對 IBinder
    //的具體實現,而我們實現的方法就是服務端提供一個方法傳遞數據"{'data':'AIDLServiceTest'}
    IServiceInterface.Stub stub = new IServiceInterface.Stub() {
        @Override
        public String getData() throws RemoteException {

            String s = "{'data':'AIDLServiceTest'}";
            return s;
        }
    };
}

3.創建 client 端

 //創建service 鏈接 
 private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iServiceInterface = IServiceInterface.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            iServiceInterface = null;
        }
    };
    //綁定
    public void bindService(Context context) {
        Intent intent = new Intent();
        intent.setAction("com.fyh.aidl");
        intent.setPackage("com.fyh.aidl.service");
        context.bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }
    //解綁

    public void unbindService(Context context) {
        if (null == iServiceInterface) {
            return;
        }
        context.unbindService(connection);
        iServiceInterface = null;
    }
    //請求服務端數據
    public String requestData() {
        if (null == iServiceInterface) {
            return null;
        }
        try {
            String data = iServiceInterface.getData();
            return data;
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return null;
    }

輸出的結果 

 通過使用 AIDL 我們會非常方便的實現進程間的通訊 同時我們可以看看自動生成的 IServiceInterface.java 文件是什麼樣的結構。

package com.fyh.aidl;


public interface IServiceInterface extends android.os.IInterface{
  
  public static class Default implements com.fyh.aidl.IServiceInterface{
    
    @Override 
    public java.lang.String getData() throws android.os.RemoteException{
      return null;
    }
    @Override
    public android.os.IBinder asBinder() {
      return null;
    }
  }
  
  public static abstract class Stub extends android.os.Binder implements com.fyh.aidl.IServiceInterface{

    private static final java.lang.String DESCRIPTOR = "com.fyh.aidl.IServiceInterface";

    
    public Stub(){
      this.attachInterface(this, DESCRIPTOR);
    }
    
    public static com.fyh.aidl.IServiceInterface asInterface(android.os.IBinder obj){
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.fyh.aidl.IServiceInterface))) {
        return ((com.fyh.aidl.IServiceInterface)iin);
      }
      return new com.fyh.aidl.IServiceInterface.Stub.Proxy(obj);
    }
    @Override 
    public android.os.IBinder asBinder(){
      return this;
    }
    @Override 
    public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException{
      java.lang.String descriptor = DESCRIPTOR;
      switch (code)
      {
        case INTERFACE_TRANSACTION:
        {
          reply.writeString(descriptor);
          return true;
        }
        case TRANSACTION_getData:
        {
          data.enforceInterface(descriptor);
          java.lang.String _result = this.getData();
          reply.writeNoException();
          reply.writeString(_result);
          return true;
        }
        default:
        {
          return super.onTransact(code, data, reply, flags);
        }
      }
    }
    private static class Proxy implements com.fyh.aidl.IServiceInterface
    {
      private android.os.IBinder mRemote;
      Proxy(android.os.IBinder remote)
      {
        mRemote = remote;
      }
      @Override public android.os.IBinder asBinder()
      {
        return mRemote;
      }
      public java.lang.String getInterfaceDescriptor()
      {
        return DESCRIPTOR;
      }
      @Override 
      public java.lang.String getData() throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        java.lang.String _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          boolean _status = mRemote.transact(Stub.TRANSACTION_getData, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().getData();
          }
          _reply.readException();
          _result = _reply.readString();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
      public static com.fyh.aidl.IServiceInterface sDefaultImpl;
    }
    static final int TRANSACTION_getData = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    public static boolean setDefaultImpl(com.fyh.aidl.IServiceInterface impl) {
      if (Stub.Proxy.sDefaultImpl == null && impl != null) {
        Stub.Proxy.sDefaultImpl = impl;
        return true;
      }
      return false;
    }
    public static com.fyh.aidl.IServiceInterface getDefaultImpl() {
      return Stub.Proxy.sDefaultImpl;
    }
  }
  /**
       * Demonstrates some basic types that you can use as parameters
       * and return values in AIDL.
       */
  public java.lang.String getData() throws android.os.RemoteException;
}

在這個類中 實現了 com.fyh.aidl.IServiceInterface 接口的 情況有三種  Default   Stub   Proxy 。當default 的時候 返回的是null。

我們在 service 中實現的 是IServiceInterface.Stub stub = new IServiceInterface.Stub() 。從代碼中我們可以看出 Stub 是一個繼承了IBinder 實現了IServiceInterface 的抽象靜態內部類,而具體的實現實在  AIDLService 中進行的。而這個 具體 的IBinder 時間對象 stub 會在客戶端綁定的時候返回給客戶端 。客戶端會調用Stub中的靜態方法asInterface,stub作爲參數,最後拿到IServiceInterface接口對象 iServiceInterface 。

然後 if (((iin!=null)&&(iin instanceof com.fyh.aidl.IServiceInterface))) 判斷客戶端和服務端是否在同一個進程下,如果在同一進程那麼asInterface()將返回Stub對象本身,因爲此時根本不需要跨進稱通信,那麼直接調用Stub對象的接口就可以了。否則返回Stub.Proxy代理對象。該對象持有着遠程的Binder引用,因爲現在需要跨進程通信。

好了介紹的比較簡單,文章主要是AIDL 的簡單實現,順便看看Android 爲我們自動生成的類裏面是什麼樣子的。如果要深入瞭解,還需要等深入的學習。

demo 地址 : https://github.com/fyhsgsgssg/AIDLTest

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章