[关闭]
@yudesong 2018-02-23T00:30:24.000000Z 字数 9164 阅读 550

AIDL

Android


  1. 创建一个接口,再里面定义方法
  1. package com.example.taidl;
  2. interface ICalcAIDL
  3. {
  4. int add(int x , int y);
  5. int min(int x , int y );
  6. }

build一下gen目录下会生成ICalcAIDL.java文件

  1. /*
  2. * This file is auto-generated. DO NOT MODIFY.
  3. * Original file: /Users/dream/Downloads/android/androidProject/TAIDL/src/com/example/taidl/ICalcAIDL.aidl
  4. */
  5. package com.example.taidl;
  6. public interface ICalcAIDL extends android.os.IInterface
  7. {
  8. /** Local-side IPC implementation stub class. */
  9. public static abstract class Stub extends android.os.Binder implements com.example.taidl.ICalcAIDL
  10. {
  11. private static final java.lang.String DESCRIPTOR = "com.example.taidl.ICalcAIDL";
  12. /** Construct the stub at attach it to the interface. */
  13. public Stub()
  14. {
  15. this.attachInterface(this, DESCRIPTOR);
  16. }
  17. /**
  18. * Cast an IBinder object into an com.example.taidl.ICalcAIDL interface,
  19. * generating a proxy if needed.
  20. */
  21. public static com.example.taidl.ICalcAIDL asInterface(android.os.IBinder obj)
  22. {
  23. if ((obj==null)) {
  24. return null;
  25. }
  26. android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
  27. if (((iin!=null)&&(iin instanceof com.example.taidl.ICalcAIDL))) {
  28. return ((com.example.taidl.ICalcAIDL)iin);
  29. }
  30. return new com.example.taidl.ICalcAIDL.Stub.Proxy(obj);
  31. }
  32. @Override public android.os.IBinder asBinder()
  33. {
  34. return this;
  35. }
  36. @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
  37. {
  38. switch (code)
  39. {
  40. case INTERFACE_TRANSACTION:
  41. {
  42. reply.writeString(DESCRIPTOR);
  43. return true;
  44. }
  45. case TRANSACTION_add:
  46. {
  47. data.enforceInterface(DESCRIPTOR);
  48. int _arg0;
  49. _arg0 = data.readInt();
  50. int _arg1;
  51. _arg1 = data.readInt();
  52. int _result = this.add(_arg0, _arg1);
  53. reply.writeNoException();
  54. reply.writeInt(_result);
  55. return true;
  56. }
  57. case TRANSACTION_min:
  58. {
  59. data.enforceInterface(DESCRIPTOR);
  60. int _arg0;
  61. _arg0 = data.readInt();
  62. int _arg1;
  63. _arg1 = data.readInt();
  64. int _result = this.min(_arg0, _arg1);
  65. reply.writeNoException();
  66. reply.writeInt(_result);
  67. return true;
  68. }
  69. }
  70. return super.onTransact(code, data, reply, flags);
  71. }
  72. private static class Proxy implements com.example.taidl.ICalcAIDL
  73. {
  74. private android.os.IBinder mRemote;
  75. Proxy(android.os.IBinder remote)
  76. {
  77. mRemote = remote;
  78. }
  79. @Override public android.os.IBinder asBinder()
  80. {
  81. return mRemote;
  82. }
  83. public java.lang.String getInterfaceDescriptor()
  84. {
  85. return DESCRIPTOR;
  86. }
  87. @Override public int add(int x, int y) throws android.os.RemoteException
  88. {
  89. android.os.Parcel _data = android.os.Parcel.obtain();
  90. android.os.Parcel _reply = android.os.Parcel.obtain();
  91. int _result;
  92. try {
  93. _data.writeInterfaceToken(DESCRIPTOR);
  94. _data.writeInt(x);
  95. _data.writeInt(y);
  96. mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
  97. _reply.readException();
  98. _result = _reply.readInt();
  99. }
  100. finally {
  101. _reply.recycle();
  102. _data.recycle();
  103. }
  104. return _result;
  105. }
  106. @Override public int min(int x, int y) throws android.os.RemoteException
  107. {
  108. android.os.Parcel _data = android.os.Parcel.obtain();
  109. android.os.Parcel _reply = android.os.Parcel.obtain();
  110. int _result;
  111. try {
  112. _data.writeInterfaceToken(DESCRIPTOR);
  113. _data.writeInt(x);
  114. _data.writeInt(y);
  115. mRemote.transact(Stub.TRANSACTION_min, _data, _reply, 0);
  116. _reply.readException();
  117. _result = _reply.readInt();
  118. }
  119. finally {
  120. _reply.recycle();
  121. _data.recycle();
  122. }
  123. return _result;
  124. }
  125. }
  126. static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
  127. static final int TRANSACTION_min = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
  128. }
  129. public int add(int x, int y) throws android.os.RemoteException;
  130. public int min(int x, int y) throws android.os.RemoteException;
  131. }
  1. 新建一个Service
  1. package com.example.taidl;
  2. import android.app.Service;
  3. import android.content.Intent;
  4. import android.os.IBinder;
  5. import android.os.RemoteException;
  6. import android.util.Log;
  7. public class CalcService extends Service{
  8. private static final String TAG = "server";
  9. public void onCreate()
  10. {
  11. Log.e(TAG, "onCreate");
  12. }
  13. public IBinder onBind(Intent t)
  14. {
  15. Log.e(TAG, "onBind");
  16. return mBinder;
  17. }
  18. public void onDestroy()
  19. {
  20. Log.e(TAG, "onDestroy");
  21. super.onDestroy();
  22. }
  23. public boolean onUnbind(Intent intent)
  24. {
  25. Log.e(TAG, "onUnbind");
  26. return super.onUnbind(intent);
  27. }
  28. public void onRebind(Intent intent)
  29. {
  30. Log.e(TAG, "onRebind");
  31. super.onRebind(intent);
  32. }
  33. private final ICalcAIDL.Stub mBinder = new ICalcAIDL.Stub() {
  34. @Override
  35. public int min(int x, int y) throws RemoteException {
  36. return x + y;
  37. }
  38. @Override
  39. public int add(int x, int y) throws RemoteException {
  40. // TODO Auto-generated method stub
  41. return x - y;
  42. }
  43. };
  44. }

创建了一个mBinder对象,并在Service的onBind方法中返回

注册:

  1. <service android:name="com.example.taidl.CalcService">
  2. <intent-filter>
  3. <action android:name="com.example.taidl.calc" />
  4. <category android:name="android.intent.category.DEFAULT" />
  5. </intent-filter>
  6. </service>

我们一会会在别的应用程序中通过Intent来查找此Service;这个不需要Activity,所以我也就没写Activity,安装完成也看不到安装图标,悄悄在后台运行着。服务端编写完毕。下面开始编写客户端:

  1. package com.example.tclient;
  2. import com.example.taidl.ICalcAIDL;
  3. import android.app.Activity;
  4. import android.content.ComponentName;
  5. import android.content.Context;
  6. import android.content.Intent;
  7. import android.content.ServiceConnection;
  8. import android.os.Bundle;
  9. import android.os.IBinder;
  10. import android.util.Log;
  11. import android.view.View;
  12. import android.widget.Toast;
  13. public class MainActivity extends Activity {
  14. private ICalcAIDL mCalcAidl;
  15. private ServiceConnection mServiceConn = new ServiceConnection()
  16. {
  17. @Override
  18. public void onServiceDisconnected(ComponentName name)
  19. {
  20. Log.e("client", "onServiceDisconnected");
  21. mCalcAidl = null;
  22. }
  23. @Override
  24. public void onServiceConnected(ComponentName name, IBinder service)
  25. {
  26. Log.e("client", "onServiceConnected");
  27. mCalcAidl = ICalcAIDL.Stub.asInterface(service);
  28. }
  29. };
  30. @Override
  31. protected void onCreate(Bundle savedInstanceState)
  32. {
  33. super.onCreate(savedInstanceState);
  34. setContentView(R.layout.activity_main);
  35. }
  36. /**
  37. * 点击BindService按钮时调用
  38. * @param view
  39. */
  40. public void bindService(View view)
  41. {
  42. Intent intent = new Intent();
  43. intent.setAction("com.example.taidl.calc");
  44. bindService(intent, mServiceConn, Context.BIND_AUTO_CREATE);
  45. }
  46. /**
  47. * 点击unBindService按钮时调用
  48. * @param view
  49. */
  50. public void unbindService(View view)
  51. {
  52. unbindService(mServiceConn);
  53. }
  54. /**
  55. * 点击12+12按钮时调用
  56. * @param view
  57. */
  58. public void addInvoked(View view) throws Exception
  59. {
  60. if (mCalcAidl != null)
  61. {
  62. int addRes = mCalcAidl.add(12, 12);
  63. Toast.makeText(this, addRes + "", Toast.LENGTH_SHORT).show();
  64. } else
  65. {
  66. Toast.makeText(this, "服务器被异常杀死,请重新绑定服务端", Toast.LENGTH_SHORT)
  67. .show();
  68. }
  69. }
  70. /**
  71. * 点击50-12按钮时调用
  72. * @param view
  73. */
  74. public void minInvoked(View view) throws Exception
  75. {
  76. if (mCalcAidl != null)
  77. {
  78. int addRes = mCalcAidl.min(50, 12);
  79. Toast.makeText(this, addRes + "", Toast.LENGTH_SHORT).show();
  80. } else
  81. {
  82. Toast.makeText(this, "服务器未绑定或被异常杀死,请重新绑定服务端", Toast.LENGTH_SHORT)
  83. .show();
  84. }
  85. }
  86. }

将服务端的aidl文件完整的复制过来,包名一定要一致。

分析AIDL生成的代码

  1. 服务端
  1. private final ICalcAIDL.Stub mBinder = new ICalcAIDL.Stub()
  2. {
  3. @Override
  4. public int add(int x, int y) throws RemoteException
  5. {
  6. return x + y;
  7. }
  8. @Override
  9. public int min(int x, int y) throws RemoteException
  10. {
  11. return x - y;
  12. }
  13. };

ICalcAILD.Stub来执行的,让我们来看看Stub这个类的声明:

  1. public static abstract class Stub extends android.os.Binder implements com.zhy.calc.aidl.ICalcAIDL

清楚的看到这个类是Binder的子类,是不是符合我们文章开通所说的服务端其实是一个Binder类的实例
接下来看它的onTransact()方法:

  1. @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
  2. {
  3. switch (code)
  4. {
  5. case INTERFACE_TRANSACTION:
  6. {
  7. reply.writeString(DESCRIPTOR);
  8. return true;
  9. }
  10. case TRANSACTION_add:
  11. {
  12. data.enforceInterface(DESCRIPTOR);
  13. int _arg0;
  14. _arg0 = data.readInt();
  15. int _arg1;
  16. _arg1 = data.readInt();
  17. int _result = this.add(_arg0, _arg1);
  18. reply.writeNoException();
  19. reply.writeInt(_result);
  20. return true;
  21. }
  22. case TRANSACTION_min:
  23. {
  24. data.enforceInterface(DESCRIPTOR);
  25. int _arg0;
  26. _arg0 = data.readInt();
  27. int _arg1;
  28. _arg1 = data.readInt();
  29. int _result = this.min(_arg0, _arg1);
  30. reply.writeNoException();
  31. reply.writeInt(_result);
  32. return true;
  33. }
  34. }
  35. return super.onTransact(code, data, reply, flags);
  36. }

文章开头也说到服务端的Binder实例会根据客户端依靠Binder驱动发来的消息,执行onTransact方法,然后由其参数决定执行服务端的代码。
可以看到onTransact有四个参数
code , data ,replay , flags

我们仔细看case TRANSACTION_min中的代码

data.enforceInterface(DESCRIPTOR);

与客户端的writeInterfaceToken对用,标识远程服务的名称

  1. int _arg0;
  2. _arg0 = data.readInt();
  3. int _arg1;
  4. _arg1 = data.readInt();

接下来分别读取了客户端传入的两个参数

  1. int _result = this.min(_arg0, _arg1);
  2. reply.writeNoException();
  3. reply.writeInt(_result);

然后执行this.min,即我们实现的min方法;返回result由reply写回。

add同理,可以看到服务端通过AIDL生成Stub的类,封装了服务端本来需要写的代码。

客户端

客户端主要通过ServiceConnected与服务端连接

  1. private ServiceConnection mServiceConn = new ServiceConnection()
  2. {
  3. @Override
  4. public void onServiceDisconnected(ComponentName name)
  5. {
  6. Log.e("client", "onServiceDisconnected");
  7. mCalcAidl = null;
  8. }
  9. @Override
  10. public void onServiceConnected(ComponentName name, IBinder service)
  11. {
  12. Log.e("client", "onServiceConnected");
  13. mCalcAidl = ICalcAIDL.Stub.asInterface(service);
  14. }
  15. };

如果你比较敏锐,应该会猜到这个onServiceConnected中的IBinder实例,其实就是我们文章开通所说的Binder驱动,也是一个Binder实例
在ICalcAIDL.Stub.asInterface中最终调用了:

  1. return new com.zhy.calc.aidl.ICalcAIDL.Stub.Proxy(obj);

这个Proxy实例传入了我们的Binder驱动,并且封装了我们调用服务端的代码,文章开头说,客户端会通过Binder驱动的transact()方法调用服务端代码

直接看Proxy中的add方法

  1. @Override public int add(int x, int y) throws android.os.RemoteException
  2. {
  3. android.os.Parcel _data = android.os.Parcel.obtain();
  4. android.os.Parcel _reply = android.os.Parcel.obtain();
  5. int _result;
  6. try {
  7. _data.writeInterfaceToken(DESCRIPTOR);
  8. _data.writeInt(x);
  9. _data.writeInt(y);
  10. mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
  11. _reply.readException();
  12. _result = _reply.readInt();
  13. }
  14. finally {
  15. _reply.recycle();
  16. _data.recycle();
  17. }
  18. return _result;
  19. }

首先声明两个Parcel对象,一个用于传递数据,一个用户接收返回的数据

  1. _data.writeInterfaceToken(DESCRIPTOR);与服务器端的enforceInterfac对应
  2. _data.writeInt(x);
  3. _data.writeInt(y);写入需要传递的参数
  4. mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);

终于看到了我们的transact方法,第一个对应服务端的code,_data,_repay分别对应服务端的data,reply,0表示是双向的

  1. _reply.readException();
  2. _result = _reply.readInt();

最后读出我们服务端返回的数据,然后return。可以看到和服务端的onTransact基本是一行一行对应的。

我们已经通过AIDL生成的代码解释了Android Binder框架的工作原理。Service的作用其实就是为我们创建Binder驱动,即服务端与客户端连接的桥梁。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注