零、完整源代码
链接: https://github.com/jx0260/TestGradle
一、创建AIDL文件
// IShopAidlInterface.aidl
package com.example.testgradle;// Declare any non-default types here with import statementsinterface IShopAidlInterface {String getProductInfo(int productNo);void buyProduct1(int productNo, String address);}
二、Make Project 生成Binder工具类
路径为:
生成代码如下(下一篇文章会分析这些生成的代码):
/** This file is auto-generated. DO NOT MODIFY.*/
package com.example.testgradle;
// Declare any non-default types here with import statementspublic 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{}@Overridepublic 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() {@Overridepublic String getProductInfo(int productNo) throws RemoteException {Log.i(TAG, "SERVER: receive productNo: " + productNo);return "the productNo is: " + productNo + ", productName is LEGO!";}@Overridepublic 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() {@Overridepublic String getProductInfo(int productNo) throws RemoteException {Log.i(TAG, "SERVER: receive productNo: " + productNo);return "the productNo is: " + productNo + ", productName is LEGO!";}@Overridepublic void buyProduct1(int productNo, String address) throws RemoteException {Log.i(TAG, "SERVER: receive productNo: " + productNo + ", address: " +address);Log.i(TAG, "YOU buy succeed!");}};@Overridepublic IBinder onBind(Intent intent) {return mBinder;}
}
我们在 onBind() 方法中,将Stub对象传出去。
manifest 文件配置一下:
<serviceandroid: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() {@Overridepublic 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();}}@Overridepublic void onServiceDisconnected(ComponentName name) {}}, BIND_AUTO_CREATE);findViewById(R.id.btn_getInfo).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {try {iShopAidlInterface.getProductInfo(1221);} catch (RemoteException e) {e.printStackTrace();}}});findViewById(R.id.btn_buy).setOnClickListener(new View.OnClickListener() {@Overridepublic 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 的关系。