Android AIDL的使用(配源码)

零、完整源代码

链接: https://github.com/jx0260/TestGradle

一、创建AIDL文件

// IShopAidlInterface.aidl
package com.example.testgradle;

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

interface IShopAidlInterface {

    String getProductInfo(int productNo);

    void buyProduct1(int productNo, String address);

}

二、Make Project 生成Binder工具类

Android AIDL的使用(配源码)_第1张图片
路径为:
Android AIDL的使用(配源码)_第2张图片
生成代码如下(下一篇文章会分析这些生成的代码):

/*
 * This file is auto-generated.  DO NOT MODIFY.
 */
package com.example.testgradle;
// Declare any non-default types here with import statements

public interface IShopAidlInterface extends android.os.IInterface
{
  /** Default implementation for IShopAidlInterface. */
  public static class Default implements com.example.testgradle.IShopAidlInterface
  {
    @Override public java.lang.String getProductInfo(int productNo) throws android.os.RemoteException
    {
      return null;
    }
    @Override public void buyProduct1(int productNo, java.lang.String address) throws android.os.RemoteException
    {
    }
    @Override
    public android.os.IBinder asBinder() {
      return null;
    }
  }
  /** Local-side IPC implementation stub class. */
  public static abstract class Stub extends android.os.Binder implements com.example.testgradle.IShopAidlInterface
  {
    private static final java.lang.String DESCRIPTOR = "com.example.testgradle.IShopAidlInterface";
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
      this.attachInterface(this, DESCRIPTOR);
    }
    /**
     * Cast an IBinder object into an com.example.testgradle.IShopAidlInterface interface,
     * generating a proxy if needed.
     */
    public static com.example.testgradle.IShopAidlInterface asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.example.testgradle.IShopAidlInterface))) {
        return ((com.example.testgradle.IShopAidlInterface)iin);
      }
      return new com.example.testgradle.IShopAidlInterface.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_getProductInfo:
        {
          data.enforceInterface(descriptor);
          int _arg0;
          _arg0 = data.readInt();
          java.lang.String _result = this.getProductInfo(_arg0);
          reply.writeNoException();
          reply.writeString(_result);
          return true;
        }
        case TRANSACTION_buyProduct1:
        {
          data.enforceInterface(descriptor);
          int _arg0;
          _arg0 = data.readInt();
          java.lang.String _arg1;
          _arg1 = data.readString();
          this.buyProduct1(_arg0, _arg1);
          reply.writeNoException();
          return true;
        }
        default:
        {
          return super.onTransact(code, data, reply, flags);
        }
      }
    }
    private static class Proxy implements com.example.testgradle.IShopAidlInterface
    {
      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 getProductInfo(int productNo) 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);
          _data.writeInt(productNo);
          boolean _status = mRemote.transact(Stub.TRANSACTION_getProductInfo, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().getProductInfo(productNo);
          }
          _reply.readException();
          _result = _reply.readString();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
      @Override public void buyProduct1(int productNo, java.lang.String address) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          _data.writeInt(productNo);
          _data.writeString(address);
          boolean _status = mRemote.transact(Stub.TRANSACTION_buyProduct1, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().buyProduct1(productNo, address);
            return;
          }
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      public static com.example.testgradle.IShopAidlInterface sDefaultImpl;
    }
    static final int TRANSACTION_getProductInfo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_buyProduct1 = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    public static boolean setDefaultImpl(com.example.testgradle.IShopAidlInterface impl) {
      // Only one user of this interface can use this function
      // at a time. This is a heuristic to detect if two different
      // users in the same process use this function.
      if (Stub.Proxy.sDefaultImpl != null) {
        throw new IllegalStateException("setDefaultImpl() called twice");
      }
      if (impl != null) {
        Stub.Proxy.sDefaultImpl = impl;
        return true;
      }
      return false;
    }
    public static com.example.testgradle.IShopAidlInterface getDefaultImpl() {
      return Stub.Proxy.sDefaultImpl;
    }
  }
  public java.lang.String getProductInfo(int productNo) throws android.os.RemoteException;
  public void buyProduct1(int productNo, java.lang.String address) throws android.os.RemoteException;
}

IShopAidlInterface这个生成的文件里面有 Stub类、Proxy类等,简单理解就是服务端(Stub)、客户端(proxy)它们为我们提供了跨进程通信的能力。为技术上的通信打通路径,唯一缺少的是业务方法的实现

三、编写服务端

3.1 实现服务端 Stub 业务

class Stub implements com.example.testgradle.IShopAidlInterface

AIDL为我们生成的Stub类,实现了 com.example.testgradle.IShopAidlInterface 接口,我们现在就实现他的业务方法:

private IShopAidlInterface.Stub mBinder = new IShopAidlInterface.Stub() {
        @Override
        public String getProductInfo(int productNo) throws RemoteException {
            Log.i(TAG, "SERVER: receive productNo: " + productNo);
            return "the productNo is: " + productNo + ", productName is LEGO!";
        }

        @Override
        public void buyProduct1(int productNo, String address) throws RemoteException {
            Log.i(TAG, "SERVER: receive productNo: " + productNo + ", address: " +address);
            Log.i(TAG, "YOU buy succeed!");
        }
    };

现在我们就实现好了,简单打印一些消息。有了服务端的Stub类,客户端怎么调用到它呢?
我们通过Android四大组件的Service,将这个服务端的Stub“传到”客户端,再在客户端进行调用:

3.2 定义服务端的Service

public class ShopService extends Service {
    private String TAG = "ShopService";

    public ShopService() {
    }

    private IShopAidlInterface.Stub mBinder = new IShopAidlInterface.Stub() {
        @Override
        public String getProductInfo(int productNo) throws RemoteException {
            Log.i(TAG, "SERVER: receive productNo: " + productNo);
            return "the productNo is: " + productNo + ", productName is LEGO!";
        }

        @Override
        public void buyProduct1(int productNo, String address) throws RemoteException {
            Log.i(TAG, "SERVER: receive productNo: " + productNo + ", address: " +address);
            Log.i(TAG, "YOU buy succeed!");
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}

我们在 onBind() 方法中,将Stub对象传出去。
manifest 文件配置一下:

<service
    android:name=".ShopService"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="com.example.testgradle.ShopService"/>
    </intent-filter>
</service>

(注意 exported=“true”,意味着允许让外部组件启动,我们要做跨进程调用,所以要允许客户端能访问此Service)

四、编写客户端

新建一个Application,创建一个Activity:
在Create() 方法中:

private IShopAidlInterface iShopAidlInterface;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_client);
	Intent serviceIntent = new Intent("com.example.testgradle.ShopService");
	serviceIntent.setPackage("com.example.testgradle");
	bindService(serviceIntent, new ServiceConnection() {
	    @Override
	    public void onServiceConnected(ComponentName name, IBinder service) {
	        Log.i("ClientActivity", "onServiceConnected() service=" + service);
	        iShopAidlInterface = IShopAidlInterface.Stub.asInterface(service);
	        try {
	            iShopAidlInterface.getProductInfo(1221);
	            iShopAidlInterface.buyProduct1(9988, "大连市甘井子区");
	        } catch (RemoteException e) {
	            e.printStackTrace();
	        }
	    }
	
	    @Override
	    public void onServiceDisconnected(ComponentName name) {
	
	    }
	}, BIND_AUTO_CREATE);
	
	findViewById(R.id.btn_getInfo).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            try {
                iShopAidlInterface.getProductInfo(1221);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    });

    findViewById(R.id.btn_buy).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            try {
                iShopAidlInterface.buyProduct1(9988, "大连市西岗区");
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    });
}

我们通过bindService,绑定到刚才在服务端定义的Service。在onServiceConnected()
回调中,将传过来的 IBinder 对象,使用 Stub.asInterface 转成 IShopAidlInterface 对象。再调用其中的业务方法。
由于我们是两个进程,所以此处的 使用 Stub.asInterface 转出的对象 就是一个 Proxy。

五、点按钮运行

打印日志:

com.example.testgradle I/ShopService: SERVER: receive productNo: 1221
com.example.testgradle I/ShopService: SERVER: receive productNo: 9988, address: 大连市西岗区
com.example.testgradle I/ShopService: YOU buy succeed!

下一篇文章,将详细描述,这中间发生了什么 及AIDL 与 Binder 的关系。

你可能感兴趣的:(Android,Framework学习,android,java,AIDL,跨进程,IPC)