AIDL (Android Interface Definition Language) 是一种接口定义语言,用于生成代码允许Android设备上的两个进程间进程通信(IPC).
如果你需要编写一个进程(比如Activity)访问另一个进程(比如Services)的对象的方法代码,你可以使用AIDL自动生成代码而不用自己配置大量的参数.
AIDL IPC基于接口机制,类似COM,Corba,且更加轻量化.它使用一个代理来在客户和实现间传递值.

Implementing IPC Using AIDL 实现进程通信IPC

分为五个步骤:
1.创建 SomeService.aidl 文件
利用aidl.exe生成接口文件.若你的IDE安装了ADT,将会在gen目录或src相应包中自动根据描述文件生成同名接口文件.否则请手动:

命令行:
adil path\SomeService.adil <CR>

注意:
1.自定义类在aidl描述文件中,即便在同一个包中,也要显式import.
2.在aidl文件中所有非Java原始类型参数必须加上标记:in, out, inout.
3.Java 原始类型默认为in,且不能为其它.
4.Java 原始类型包括为java.lang, java,util包中包括的类.
5.接口名同aidl文件名.
6.接口前不用加访问权限修饰符public ,private, protected等,也不能用final ,static.


接口文件分析:

接口中生成一个Stub的抽象类,里面包括aidl定义的方法.还包括一些其它辅助方法.值得关注的是asInterface(IBinder iBinder),它返回接口的实例.

2.实现接口
接口的实现需继承接口.Stub.并实现Stub类的方法.
下面给出一个使用匿名方式实现的例子.

private final SomeService.Stub binder = new SomeService.Stub(){
public void service(){
//...
}
}

注意:
1.没有异常会正常返回
2.RPC通常比较耗时且是异步的,因此应该在线程中调用RPC服务.
3.只支持方法,不支持静态字段.

3.暴露接口给客户
客户要服务,当然要知道在哪有服务.通常一台服务器可能提供不止一个服务.因些,我们使用
RomoteService来管理所有远程服务.
暴露服务必须继承Service.并实现onBind()方法.

Java代码
  1. public class RemoteService extends Service{
  2. ...
  3. @Override
  4. public IBinderonBind(Intentintent){
  5. //Selecttheinterfacetoreturn.Ifyourserviceonlyimplements
  6. //asingleinterface,youcanjustreturnitherewithoutchecking
  7. //theIntent.
  8. if (SomeService. class .getName().equals(intent.getAction())){
  9. return mBinder;
  10. }
  11. if (ISecondary. class .getName().equals(intent.getAction())){
  12. return mSecondaryBinder;
  13. }
  14. return null ;
  15. }
  16. /**
  17. *TheSomeServiceInterfaceisdefinedthroughIDL
  18. */
  19. private final SomeService.StubmBinder= new SomeService.Stub(){
  20. public void registerCallback(SomeServiceCallbackcb){
  21. if (cb!= null )mCallbacks.register(cb);
  22. }
  23. public void unregisterCallback(SomeServiceCallbackcb){
  24. if (cb!= null )mCallbacks.unregister(cb);
  25. }
  26. };
  27. /**
  28. *Asecondaryinterfacetotheservice.
  29. */
  30. private final ISecondary.StubmSecondaryBinder= new ISecondary.Stub(){
  31. public int getPid(){
  32. return Process.myPid();
  33. }
  34. public void basicTypes( int anInt, long aLong, boolean aBoolean,
  35. float aFloat, double aDouble,StringaString){
  36. }
  37. };
  38. }
public class RemoteService extends Service {...    @Override    public IBinder onBind(Intent intent) {        // Select the interface to return.  If your service only implements        // a single interface, you can just return it here without checking        // the Intent.        if (SomeService.class.getName().equals(intent.getAction())) {            return mBinder;        }        if (ISecondary.class.getName().equals(intent.getAction())) {            return mSecondaryBinder;        }        return null;    }    /**     * The SomeService Interface is defined through IDL     */    private final SomeService.Stub mBinder = new SomeService.Stub() {        public void registerCallback(SomeServiceCallback cb) {            if (cb != null) mCallbacks.register(cb);        }        public void unregisterCallback(SomeServiceCallback cb) {            if (cb != null) mCallbacks.unregister(cb);        }    };    /**     * A secondary interface to the service.     */    private final ISecondary.Stub mSecondaryBinder = new ISecondary.Stub() {        public int getPid() {            return Process.myPid();        }        public void basicTypes(int anInt, long aLong, boolean aBoolean,                float aFloat, double aDouble, String aString) {        }    };}



这样暴露好了服务,接着做什么?当然是调用服务了.

调用之前,有必要了解下 对象打包,类似与Java的对象序列化.

4.使用打包传送参数


如果一个类要使用打包功能(类似对象序列化),要实现如下5个步骤:

4.1 实现 Parcelable接口
4.2 实现 public void writeToParcel(Parcel out) 方法
4.3 实现 public void readFromParcel(Parcel in) 方法
4.4 添加一个静态字段 CREATOR 到实现 Parcelable.Creator 接口的类中
4.5 创建一个aidl文件声明你的可打包的类

示例:
Rect.java

Java代码
  1. import android.os.Parcel;
  2. import android.os.Parcelable;
  3. public final class Rect implements Parcelable{
  4. public int left;
  5. public int top;
  6. public int right;
  7. public int bottom;
  8. public static final Parcelable.Creator<Rect>CREATOR= new Parcelable.Creator<Rect>(){
  9. public RectcreateFromParcel(Parcelin){
  10. return new Rect(in);
  11. }
  12. public Rect[]newArray( int size){
  13. return new Rect[size];
  14. }
  15. };
  16. public Rect(){
  17. }
  18. private Rect(Parcelin){
  19. readFromParcel(in);
  20. }
  21. public void writeToParcel(Parcelout){
  22. out.writeInt(left);
  23. out.writeInt(top);
  24. out.writeInt(right);
  25. out.writeInt(bottom);
  26. }
  27. public void readFromParcel(Parcelin){
  28. left=in.readInt();
  29. top=in.readInt();
  30. right=in.readInt();
  31. bottom=in.readInt();
  32. }
  33. }
import android.os.Parcel;import android.os.Parcelable;public final class Rect implements Parcelable {    public int left;    public int top;    public int right;    public int bottom;    public static final Parcelable.Creator<Rect> CREATOR = new Parcelable.Creator<Rect>() {        public Rect createFromParcel(Parcel in) {            return new Rect(in);        }        public Rect[] newArray(int size) {            return new Rect[size];        }    };    public Rect() {    }    private Rect(Parcel in) {        readFromParcel(in);    }    public void writeToParcel(Parcel out) {        out.writeInt(left);        out.writeInt(top);        out.writeInt(right);        out.writeInt(bottom);    }    public void readFromParcel(Parcel in) {        left = in.readInt();        top = in.readInt();        right = in.readInt();        bottom = in.readInt();    }}



Rect.aidl

Java代码
  1. package android.graphics;
  2. //DeclareRectsoAIDLcanfinditandknowsthatitimplements
  3. //theparcelableprotocol.
  4. parcelableRect;
package android.graphics;// Declare Rect so AIDL can find it and knows that it implements// the parcelable protocol.parcelable Rect;



注意:
参数一定不能越界.

5.调用IPC方法
调用IPC方法还有6个步骤:
如果觉得烦,那就尽力弄懂,不然你不晕,我译得也晕..

5.1 声明aidl定义的接口类型引用
5.2 实现 ServiceConnection
5.3 调用 Context.bindService(),传入 ServiceConnection 的实现
5.4 在你的 ServiceConnection.onServiceConnected(),你将得到一个 IBinder 实例(service). 调用 YourInterfaceName.Stub.asInterface((IBinder)service)强制转换 YourInterface 类型.
5.5 调用接口定义的方法.你应该始终小心 DeadObjectException 异常,当连接不成功或中断它就会抛出,这也是远程对象唯一的一个异常.
5.6 断开连接,调用 Context.unbindService().

注解:
你可以使用匿名对象作为参数.
对象是引用计数.

ApiDemos 有个子the Remote Activity 的例子.

Java代码
  1. public class RemoteServiceBinding extends Activity{
  2. /**Theprimaryinterfacewewillbecallingontheservice.*/
  3. IRemoteServicemService= null ;
  4. /**Anotherinterfaceweuseontheservice.*/
  5. ISecondarymSecondaryService= null ;
  6. ButtonmKillButton;
  7. TextViewmCallbackText;
  8. private boolean mIsBound;
  9. /**
  10. *Standardinitializationofthisactivity.SetuptheUI,thenwait
  11. *fortheusertopokeitbeforedoinganything.
  12. */
  13. @Override
  14. protected void onCreate(BundlesavedInstanceState){
  15. super .onCreate(savedInstanceState);
  16. setContentView(R.layout.remote_service_binding);
  17. //Watchforbuttonclicks.
  18. Buttonbutton=(Button)findViewById(R.id.bind);
  19. button.setOnClickListener(mBindListener);
  20. button=(Button)findViewById(R.id.unbind);
  21. button.setOnClickListener(mUnbindListener);
  22. mKillButton=(Button)findViewById(R.id.kill);
  23. mKillButton.setOnClickListener(mKillListener);
  24. mKillButton.setEnabled( false );
  25. mCallbackText=(TextView)findViewById(R.id.callback);
  26. mCallbackText.setText( "Notattached." );
  27. }
  28. /**
  29. *Classforinteractingwiththemaininterfaceoftheservice.
  30. */
  31. private ServiceConnectionmConnection= new ServiceConnection(){
  32. public void onServiceConnected(ComponentNameclassName,
  33. IBinderservice){
  34. //Thisiscalledwhentheconnectionwiththeservicehasbeen
  35. //established,givingustheserviceobjectwecanuseto
  36. //interactwiththeservice.Wearecommunicatingwithour
  37. //servicethroughanIDLinterface,sogetaclient-side
  38. //representationofthatfromtherawserviceobject.
  39. mService=IRemoteService.Stub.asInterface(service);
  40. mKillButton.setEnabled( true );
  41. mCallbackText.setText( "Attached." );
  42. //Wewanttomonitortheserviceforaslongasweare
  43. //connectedtoit.
  44. try {
  45. mService.registerCallback(mCallback);
  46. } catch (RemoteExceptione){
  47. //Inthiscasetheservicehascrashedbeforewecouldeven
  48. //doanythingwithit;wecancountonsoonbeing
  49. //disconnected(andthenreconnectedifitcanberestarted)
  50. //sothereisnoneedtodoanythinghere.
  51. }
  52. //Aspartofthesample,telltheuserwhathappened.
  53. Toast.makeText(RemoteServiceBinding. this ,R.string.remote_service_connected,
  54. Toast.LENGTH_SHORT).show();
  55. }
  56. public void onServiceDisconnected(ComponentNameclassName){
  57. //Thisiscalledwhentheconnectionwiththeservicehasbeen
  58. //unexpectedlydisconnected--thatis,itsprocesscrashed.
  59. mService= null ;
  60. mKillButton.setEnabled( false );
  61. mCallbackText.setText( "Disconnected." );
  62. //Aspartofthesample,telltheuserwhathappened.
  63. Toast.makeText(RemoteServiceBinding. this ,R.string.remote_service_disconnected,
  64. Toast.LENGTH_SHORT).show();
  65. }
  66. };
  67. /**
  68. *Classforinteractingwiththesecondaryinterfaceoftheservice.
  69. */
  70. private ServiceConnectionmSecondaryConnection= new ServiceConnection(){
  71. public void onServiceConnected(ComponentNameclassName,
  72. IBinderservice){
  73. //Connectingtoasecondaryinterfaceisthesameasany
  74. //otherinterface.
  75. mSecondaryService=ISecondary.Stub.asInterface(service);
  76. mKillButton.setEnabled( true );
  77. }
  78. public void onServiceDisconnected(ComponentNameclassName){
  79. mSecondaryService= null ;
  80. mKillButton.setEnabled( false );
  81. }
  82. };
  83. private OnClickListenermBindListener= new OnClickListener(){
  84. public void onClick(Viewv){
  85. //Establishacoupleconnectionswiththeservice,binding
  86. //byinterfacenames.Thisallowsotherapplicationstobe
  87. //installedthatreplacetheremoteservicebyimplementing
  88. //thesameinterface.
  89. bindService( new Intent(IRemoteService. class .getName()),
  90. mConnection,Context.BIND_AUTO_CREATE);
  91. bindService( new Intent(ISecondary. class .getName()),
  92. mSecondaryConnection,Context.BIND_AUTO_CREATE);
  93. mIsBound= true ;
  94. mCallbackText.setText( "Binding." );
  95. }
  96. };
  97. private OnClickListenermUnbindListener= new OnClickListener(){
  98. public void onClick(Viewv){
  99. if (mIsBound){
  100. //Ifwehavereceivedtheservice,andhenceregisteredwith
  101. //it,thennowisthetimetounregister.
  102. if (mService!= null ){
  103. try {
  104. mService.unregisterCallback(mCallback);
  105. } catch (RemoteExceptione){
  106. //Thereisnothingspecialweneedtodoiftheservice
  107. //hascrashed.
  108. }
  109. }
  110. //Detachourexistingconnection.
  111. unbindService(mConnection);
  112. unbindService(mSecondaryConnection);
  113. mKillButton.setEnabled( false );
  114. mIsBound= false ;
  115. mCallbackText.setText( "Unbinding." );
  116. }
  117. }
  118. };
  119. private OnClickListenermKillListener= new OnClickListener(){
  120. public void onClick(Viewv){
  121. //Tokilltheprocesshostingourservice,weneedtoknowits
  122. //PID.Convenientlyourservicehasacallthatwillreturn
  123. //tousthatinformation.
  124. if (mSecondaryService!= null ){
  125. try {
  126. int pid=mSecondaryService.getPid();
  127. //Notethat,thoughthisAPIallowsustorequestto
  128. //killanyprocessbasedonitsPID,thekernelwill
  129. //stillimposestandardrestrictionsonwhichPIDsyou
  130. //areactuallyabletokill.Typicallythismeansonly
  131. //theprocessrunningyourapplicationandanyadditional
  132. //processescreatedbythatappasshownhere;packages
  133. //sharingacommonUIDwillalsobeabletokilleach
  134. //other'sprocesses.
  135. Process.killProcess(pid);
  136. mCallbackText.setText( "Killedserviceprocess." );
  137. } catch (RemoteExceptionex){
  138. //Recovergracefullyfromtheprocesshostingthe
  139. //serverdying.
  140. //Justforpurposesofthesample,putupanotification.
  141. Toast.makeText(RemoteServiceBinding. this ,
  142. R.string.remote_call_failed,
  143. Toast.LENGTH_SHORT).show();
  144. }
  145. }
  146. }
  147. };
  148. //----------------------------------------------------------------------
  149. //Codeshowinghowtodealwithcallbacks.
  150. //----------------------------------------------------------------------
  151. /**
  152. *Thisimplementationisusedtoreceivecallbacksfromtheremote
  153. *service.
  154. */
  155. private IRemoteServiceCallbackmCallback= new IRemoteServiceCallback.Stub(){
  156. /**
  157. *Thisiscalledbytheremoteserviceregularlytotellusabout
  158. *newvalues.NotethatIPCcallsaredispatchedthroughathread
  159. *poolrunningineachprocess,sothecodeexecutingherewill
  160. *NOTberunninginourmainthreadlikemostotherthings--so,
  161. *toupdatetheUI,weneedtouseaHandlertohopoverthere.
  162. */
  163. public void valueChanged( int value){
  164. mHandler.sendMessage(mHandler.obtainMessage(BUMP_MSG,value, 0 ));
  165. }
  166. };
  167. private static final int BUMP_MSG= 1 ;
  168. private HandlermHandler= new Handler(){
  169. @Override public void handleMessage(Messagemsg){
  170. switch (msg.what){
  171. case BUMP_MSG:
  172. mCallbackText.setText( "Receivedfromservice:" +msg.arg1);
  173. break ;
  174. default :
  175. super .handleMessage(msg);
  176. }
  177. }
  178. };
  179. }

更多相关文章

  1. Android开发——说说Adapter那点事
  2. Android调用系统相机和图库
  3. Android实现语音识别
  4. Android实现图表绘制和展示
  5. android实现推送实践
  6. android Activity实现从底部弹出或滑出选择菜单或窗口
  7. Android(安卓)GPS学习笔记—HAL实现
  8. Android(安卓)实现QQ第三方登录
  9. 浅谈Java中Collections.sort对List排序的两种方法

随机推荐

  1. ORACLE PL/SQL编程详解之二:PL/SQL块结构
  2. SQL优化(待完善)
  3. Python自动化拉取Mysql数据并装载到Oracl
  4. 最新MySQL安装配置教程
  5. mysql获取当前时间、秒数
  6. mysql更新触发器先插入另一张表然后删除
  7. 像Farmville这样的在线游戏使用什么数据
  8. 求 Log Explorer for SQL Server 4.2 注
  9. 求一条sql语句:计算两列的差值,以及各个差
  10. mysql不能用limit的问题