`
444878909
  • 浏览: 641677 次
文章分类
社区版块
存档分类
最新评论

使用 AIDL实现通信

 
阅读更多

在Android中,如果我们需要在不同进程间实现通信,就需要用到AIDL技术去完成。

AIDL(Android Interface Definition Language)是一种接口定义语言,编译器通过*.aidl文件的描述信息生成符合通信协议的Java代码,我们无需自己去写这段繁杂的代码,只需要在需要的时候调用即可,通过这种方式我们就可以完成进程间的通信工作。关于AIDL的编写规则我在这里就不多介绍了,读者可以到网上查找一下相关资料。

接下来,我就演示一个操作AIDL的最基本的流程。

首先,我们需要建立一个服务端的工程,如图所以:

在IPerson.aidl中我们定义了一个“问候”的方法,代码如下:

  1. packagecom.scott.aidl;
  2. interfaceIPerson{
  3. Stringgreet(Stringsomeone);
  4. }

在Eclipse插件的帮助下,编译器会自动在gen目录中生成对应的IPerson.java文件,格式化后的代码如下:

  1. packagecom.scott.aidl;
  2. publicinterfaceIPersonextendsandroid.os.IInterface{
  3. /**Local-sideIPCimplementationstubclass.*/
  4. publicstaticabstractclassStubextendsandroid.os.Binderimplementscom.scott.aidl.IPerson{
  5. privatestaticfinaljava.lang.StringDESCRIPTOR="com.scott.aidl.IPerson";
  6. /**Constructthestubatattachittotheinterface.*/
  7. publicStub(){
  8. this.attachInterface(this,DESCRIPTOR);
  9. }
  10. /**
  11. *CastanIBinderobjectintoancom.scott.aidl.IPersoninterface,
  12. *generatingaproxyifneeded.
  13. */
  14. publicstaticcom.scott.aidl.IPersonasInterface(android.os.IBinderobj){
  15. if((obj==null)){
  16. returnnull;
  17. }
  18. android.os.IInterfaceiin=(android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
  19. if(((iin!=null)&&(iininstanceofcom.scott.aidl.IPerson))){
  20. return((com.scott.aidl.IPerson)iin);
  21. }
  22. returnnewcom.scott.aidl.IPerson.Stub.Proxy(obj);
  23. }
  24. publicandroid.os.IBinderasBinder(){
  25. returnthis;
  26. }
  27. @Override
  28. publicbooleanonTransact(intcode,android.os.Parceldata,android.os.Parcelreply,intflags)
  29. throwsandroid.os.RemoteException{
  30. switch(code){
  31. caseINTERFACE_TRANSACTION:{
  32. reply.writeString(DESCRIPTOR);
  33. returntrue;
  34. }
  35. caseTRANSACTION_greet:{
  36. data.enforceInterface(DESCRIPTOR);
  37. java.lang.String_arg0;
  38. _arg0=data.readString();
  39. java.lang.String_result=this.greet(_arg0);
  40. reply.writeNoException();
  41. reply.writeString(_result);
  42. returntrue;
  43. }
  44. }
  45. returnsuper.onTransact(code,data,reply,flags);
  46. }
  47. privatestaticclassProxyimplementscom.scott.aidl.IPerson{
  48. privateandroid.os.IBindermRemote;
  49. Proxy(android.os.IBinderremote){
  50. mRemote=remote;
  51. }
  52. publicandroid.os.IBinderasBinder(){
  53. returnmRemote;
  54. }
  55. publicjava.lang.StringgetInterfaceDescriptor(){
  56. returnDESCRIPTOR;
  57. }
  58. publicjava.lang.Stringgreet(java.lang.Stringsomeone)throwsandroid.os.RemoteException{
  59. android.os.Parcel_data=android.os.Parcel.obtain();
  60. android.os.Parcel_reply=android.os.Parcel.obtain();
  61. java.lang.String_result;
  62. try{
  63. _data.writeInterfaceToken(DESCRIPTOR);
  64. _data.writeString(someone);
  65. mRemote.transact(Stub.TRANSACTION_greet,_data,_reply,0);
  66. _reply.readException();
  67. _result=_reply.readString();
  68. }finally{
  69. _reply.recycle();
  70. _data.recycle();
  71. }
  72. return_result;
  73. }
  74. }
  75. staticfinalintTRANSACTION_greet=(android.os.IBinder.FIRST_CALL_TRANSACTION+0);
  76. }
  77. publicjava.lang.Stringgreet(java.lang.Stringsomeone)throwsandroid.os.RemoteException;
  78. }

该文件的大纲视图如下:

IPerson接口中的抽象内部类Stub继承android.os.Binder类并实现IPerson接口,比较重要的方法是asInterface(IBinder)方法,该方法会将IBinder类型的对象转换成IPerson类型,必要的时候生成一个代理对象返回结果。

接下来就是我们的Service了:

  1. packagecom.scott.server;
  2. importandroid.app.Service;
  3. importandroid.content.Intent;
  4. importandroid.os.IBinder;
  5. importandroid.os.RemoteException;
  6. importandroid.util.Log;
  7. importcom.scott.aidl.IPerson;
  8. publicclassAIDLServiceextendsService{
  9. privatestaticfinalStringTAG="AIDLService";
  10. IPerson.Stubstub=newIPerson.Stub(){
  11. @Override
  12. publicStringgreet(Stringsomeone)throwsRemoteException{
  13. Log.i(TAG,"greet()called");
  14. return"hello,"+someone;
  15. }
  16. };
  17. @Override
  18. publicIBinderonBind(Intentintent){
  19. Log.i(TAG,"onBind()called");
  20. returnstub;
  21. }
  22. @Override
  23. publicbooleanonUnbind(Intentintent){
  24. Log.i(TAG,"onUnbind()called");
  25. returntrue;
  26. }
  27. @Override
  28. publicvoidonDestroy(){
  29. super.onDestroy();
  30. Log.i(TAG,"onDestroy()called");
  31. }
  32. }

我们实现了IPerson.Stub这个抽象类的greet方法,然后再onBind(Intent)方法中返回我们的stub实例,这样一来调用方获取的IPerson.Stub就是我们的这个实例,greet方法也会按照我们的期望那样执行。

当然,要想让Service生效,我们还需要在AndroidManifest.xml中做一些配置工作:

  1. <serviceandroid:name=".AIDLService">
  2. <intent-filter>
  3. <actionandroid:name="android.intent.action.AIDLService"/>
  4. <categoryandroid:name="android.intent.category.DEFAULT"/>
  5. </intent-filter>
  6. </service>

服务端已经完成了,接下来我们就该完成客户端的工作了。我已经建好了一个客户端工程,如图:

我们只需要把IPerson.aidl文件拷到相应的目录中即可,编译器同样会生成相对应的IPerson.java文件,这一部分和服务端没什么区别。这样一来,服务端和客户端就在通信协议上达到了统一。我们主要工作在MainActivity中完成。

MainActivity代码如下:

  1. packagecom.scott.client;
  2. importandroid.app.Activity;
  3. importandroid.content.ComponentName;
  4. importandroid.content.Context;
  5. importandroid.content.Intent;
  6. importandroid.content.ServiceConnection;
  7. importandroid.os.Bundle;
  8. importandroid.os.IBinder;
  9. importandroid.os.RemoteException;
  10. importandroid.util.Log;
  11. importandroid.view.View;
  12. importandroid.widget.Button;
  13. importandroid.widget.Toast;
  14. importcom.scott.aidl.IPerson;
  15. publicclassMainActivityextendsActivity{
  16. privateButtonbindBtn;
  17. privateButtongreetBtn;
  18. privateButtonunbindBtn;
  19. privateIPersonperson;
  20. privateServiceConnectionconn=newServiceConnection(){
  21. @Override
  22. publicvoidonServiceConnected(ComponentNamename,IBinderservice){
  23. Log.i("ServiceConnection","onServiceConnected()called");
  24. person=IPerson.Stub.asInterface(service);
  25. }
  26. @Override
  27. publicvoidonServiceDisconnected(ComponentNamename){
  28. //Thisiscalledwhentheconnectionwiththeservicehasbeenunexpectedlydisconnected,
  29. //thatis,itsprocesscrashed.Becauseitisrunninginoursameprocess,weshouldneverseethishappen.
  30. Log.i("ServiceConnection","onServiceDisconnected()called");
  31. }
  32. };
  33. @Override
  34. publicvoidonCreate(BundlesavedInstanceState){
  35. super.onCreate(savedInstanceState);
  36. setContentView(R.layout.main);
  37. bindBtn=(Button)findViewById(R.id.bindBtn);
  38. bindBtn.setOnClickListener(newView.OnClickListener(){
  39. @Override
  40. publicvoidonClick(Viewv){
  41. Intentintent=newIntent("android.intent.action.AIDLService");
  42. bindService(intent,conn,Context.BIND_AUTO_CREATE);
  43. bindBtn.setEnabled(false);
  44. greetBtn.setEnabled(true);
  45. unbindBtn.setEnabled(true);
  46. }
  47. });
  48. greetBtn=(Button)findViewById(R.id.greetBtn);
  49. greetBtn.setOnClickListener(newView.OnClickListener(){
  50. @Override
  51. publicvoidonClick(Viewv){
  52. try{
  53. StringretVal=person.greet("scott");
  54. Toast.makeText(MainActivity.this,retVal,Toast.LENGTH_SHORT).show();
  55. }catch(RemoteExceptione){
  56. Toast.makeText(MainActivity.this,"error",Toast.LENGTH_SHORT).show();
  57. }
  58. }
  59. });
  60. unbindBtn=(Button)findViewById(R.id.unbindBtn);
  61. unbindBtn.setOnClickListener(newView.OnClickListener(){
  62. @Override
  63. publicvoidonClick(Viewv){
  64. unbindService(conn);
  65. bindBtn.setEnabled(true);
  66. greetBtn.setEnabled(false);
  67. unbindBtn.setEnabled(false);
  68. }
  69. });
  70. }
  71. }

从代码中可以看到,我们要重写ServiceConnection中的onServiceConnected方法将IBinder类型的对像转换成我们的IPerson类型。到现在我们就剩下最后一个步骤了,这个环节也是最为关键的,就是绑定我们需要的服务。我们通过服务端Service定义的“android.intent.action.AIDLService”这个标识符来绑定其服务,这样客户端和服务端就实现了通信的连接,我们就可以调用IPerson中的“问候”方法了。

最后,贴几张客户端演示过程图。

按照顺序分别是:初始界面;点击bindService后界面;点击greet后界面;点击unbindService后界面。

操作过程中的日志如下:


转载:http://blog.csdn.net/liuhe688/article/details/6400385

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics