为使应用程序之间能够彼此通信,Android提供了IPC (Inter Process Communication,进程间通信)的一种独特实现: AIDL (Android Interface Definition Language, Android接口定义语言)。

建立两个Android项目,一个是client,一个是server(提供service)。

这篇文章将通过一个项目来介绍AIDL用法,包含了service和client。可能简单了些,不过轻省许多。

本文提供了一个关于AIDL使用的简单易懂的例子,分为客户端和服务端两部分,分别为客户端和服务端新建一个eclipse工程,实现了从客户端向服务端发送请求,服务端打印log的功能。

客户端和服务端的源码结构如下:

Android AIDL例子Android AIDL例子

注意,由于客户端和服务端的aidl文件所在包名必须一样,而两个包名一样的程序在安装时会产生冲突,所以这里用了一个技巧,在客户端工程的AndroidManifest.xml里把包名指定为com.styleflying,所以大家就会看到gen目录下的R.java所在的包是com.styleflying而不是com.styleflying.AIDL

现在客户端和服务端工程分别新建一个aidl接口,所在包和文件名必须一样。两个aidl接口是一样的,内容如下:

packagecom.styleflying.AIDL;interfacemInterface{voidinvokTest();}

自动编译生成.java文件如下:

packagecom.styleflying.AIDL;publicinterfacemInterfaceextendsIInterface{/**Local-sideIPCimplementationstubclass.*/publicstaticabstractclassStubextendsBinderimplementsmInterface{privatestaticfinalStringDESCRIPTOR="com.styleflying.AIDL.mInterface";/**Constructthestubatattachittotheinterface.*/publicStub(){this.attachInterface(this,DESCRIPTOR);}/***CastanIBinderobjectintoancom.styleflying.AIDL.mInterfaceinterface,*generatingaproxyifneeded.*/publicstaticmInterfaceasInterface(IBinderobj){if((obj==null)){returnnull;}IInterfaceiin=(IInterface)obj.queryLocalInterface(DESCRIPTOR);if(((iin!=null)&&(iininstanceofmInterface))){return((com.styleflying.AIDL.mInterface)iin);}returnnewcom.styleflying.AIDL.mInterface.Stub.Proxy(obj);}publicandroid.os.IBinderasBinder(){returnthis;}@OverridepublicbooleanonTransact(intcode,Parceldata,Parcelreply,intflags)throwsRemoteException{switch(code){caseINTERFACE_TRANSACTION:reply.writeString(DESCRIPTOR);returntrue;caseTRANSACTION_invokTest:data.enforceInterface(DESCRIPTOR);this.invokTest();reply.writeNoException();returntrue;}returnsuper.onTransact(code,data,reply,flags);}privatestaticclassProxyimplementsmInterface{privateIBindermRemote;Proxy(IBinderremote){mRemote=remote;}publicIBinderasBinder(){returnmRemote;}publicStringgetInterfaceDescriptor(){returnDESCRIPTOR;}publicvoidinvokTest()throwsRemoteException{Parcel_data=Parcel.obtain();Parcel_reply=Parcel.obtain();try{_data.writeInterfaceToken(DESCRIPTOR);mRemote.transact(Stub.TRANSACTION_invokTest,_data,_reply,0);_reply.readException();}finally{_reply.recycle();_data.recycle();}}}staticfinalintTRANSACTION_invokTest=(IBinder.FIRST_CALL_TRANSACTION+0);}publicvoidinvokTest()throwsRemoteException;}

客户端的mAIDLActivity.java如下:

packagecom.styleflying.AIDL;importandroid.app.Activity;importandroid.content.ComponentName;importandroid.content.Context;importandroid.content.Intent;importandroid.content.ServiceConnection;importandroid.os.Bundle;importandroid.os.IBinder;importandroid.os.RemoteException;importandroid.util.Log;importandroid.view.View;importandroid.view.View.OnClickListener;importandroid.widget.Button;importandroid.widget.Toast;importcom.styleflying.R;publicclassmAIDLActivityextendsActivity{privatestaticfinalStringTAG="AIDLActivity";privateButtonbtnOk;privateButtonbtnCancel;privateButtonbtnCallBack;privatevoidLog(Stringstr){Log.d(TAG,"----------"+str+"----------");}mInterfacemService;privateServiceConnectionmConnection=newServiceConnection(){publicvoidonServiceConnected(ComponentNameclassName,IBinderservice){Log("connectservice");mService=mInterface.Stub.asInterface(service);}publicvoidonServiceDisconnected(ComponentNameclassName){Log("disconnectservice");mService=null;}};/**Calledwhentheactivityisfirstcreated.*/@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);btnOk=(Button)findViewById(R.id.btn_ok);btnCancel=(Button)findViewById(R.id.btn_cancel);btnCallBack=(Button)findViewById(R.id.btn_callback);btnOk.setOnClickListener(newOnClickListener(){publicvoidonClick(Viewv){Bundleargs=newBundle();Intentintent=newIntent("com.styleflying.AIDL.service");intent.putExtras(args);bindService(intent,mConnection,Context.BIND_AUTO_CREATE);}});btnCancel.setOnClickListener(newOnClickListener(){publicvoidonClick(Viewv){unbindService(mConnection);}});btnCallBack.setOnClickListener(newOnClickListener(){publicvoidonClick(Viewv){try{Log.i(TAG,"currentThreadid="+Thread.currentThread().getId());mService.invokTest();}catch(RemoteExceptione){}}});}}

客户端在执行bindService的时候,成功绑定服务之后,会回调mConnection的onServiceConnected(),并且传回了服务端的通信接口IBinder,此IBinder即服务onBind()时返回的IBinder,详见mAIDLService.java。

在onServiceConnected(),客户端成功获取了服务端通信接口,实际上是本地代理对象,该对象存在于客户端进程空间,客户端只和代理对象交互,真正的IPC通信是本地代理对象和服务端的通信。

mAIDLService.java如下:

packagecom.styleflying.AIDL;importandroid.app.Service;importandroid.content.Intent;importandroid.os.IBinder;importandroid.os.Looper;importandroid.os.RemoteException;importandroid.util.Log;importandroid.widget.Toast;publicclassmAIDLServiceextendsService{privatestaticfinalStringTAG="AIDLService";privatevoidLog(Stringstr){Log.i(TAG,"----------"+str+"----------");}publicvoidonCreate(){Log("servicecreated");}publicvoidonStart(Intentintent,intstartId){Log("servicestartedid="+startId);}publicIBinderonBind(Intentt){Log("serviceonbind");returnmBinder;}publicvoidonDestroy(){Log("serviceondestroy");super.onDestroy();}publicbooleanonUnbind(Intentintent){Log("serviceonunbind");returnsuper.onUnbind(intent);}publicvoidonRebind(Intentintent){Log("serviceonrebind");super.onRebind(intent);}privatefinalmInterface.StubmBinder=newmInterface.Stub(){publicvoidinvokTest()throwsRemoteException{//TODOAuto-generatedmethodstubLog.e(TAG,"remotecallfromclient!currentthreadid="+Thread.currentThread().getId());}};}

注意onBind()函数,返回了mBinder,而mBinder实现了mInterface.Stub,实现了mInterface接口,执行了打印log的操作。

整个交互流程如下:

1)客户端通过绑定服务,获取了服务的句柄(本地代理对象);

2)客户端执行onClick(),调用本地代理对象的invokTest()函数,本地代理对象调用mRemote.transact()发出远程调用请求(见 mInterface.java);

3)服务端响应onTransact()执行this.invokTest(),并将执行结果返回;

由于客户端只和本地代理对象即服务句柄通信,由代理对象进行真正的IPC操作,所以对客户端来说,IPC过程是透明的,调用远程操作如同调用本地操作一样。在客户端调用transact()时,会将服务描述DSCRIPTION写入到data里,在客户端onTransact时会验证,如果两个不一样,则不能通信。而DSCRIPTION是根据mInterface包名和接口名自动生成的,这就是为什么两个工程里的mInterface.aidl要在同一个包的原因。

在这个过程中,mInterface.aidl起到了桥梁的作用,规定统一了客户端和服务端的通信接口,使得客户端和服务端得以成功的通信。

具体的通信transact和onTransact的过程也就是利用Binder驱动通信的过程,在这里就不多叙述。

最后补上两个工程的AndroidManifest.xml

<?xmlversion="1.0"encoding="utf-8"?><manifestxmlns:android="http://schemas.android.com/apk/res/android"package="com.styleflying"android:versionCode="1"android:versionName="1.0"><applicationandroid:icon="@drawable/icon"android:label="@string/app_name"><activityandroid:name=".AIDL.mAIDLActivity"android:label="@string/app_name"><intent-filter><actionandroid:name="android.intent.action.MAIN"/><categoryandroid:name="android.intent.category.LAUNCHER"/></intent-filter></activity></application><uses-sdkandroid:minSdkVersion="8"/></manifest>
<?xmlversion="1.0"encoding="utf-8"?><manifestxmlns:android="http://schemas.android.com/apk/res/android"package="com.styleflying.AIDL"android:versionCode="1"android:versionName="1.0"><applicationandroid:icon="@drawable/icon"android:label="@string/app_name"><serviceandroid:name=".mAIDLService"><intent-filter><actionandroid:name="com.styleflying.AIDL.service"/><categoryandroid:name="android.intent.category.DEFAULT"/></intent-filter></service></application><uses-sdkandroid:minSdkVersion="8"/></manifest>


更多相关文章

  1. Android上传文件,客户端+服务器源码
  2. Android 的网络编程(15)-Http JSon服务器端和客户端通信
  3. unity向android通信
  4. Android 博客园客户端 (一) 基本界面
  5. android微博客户端源代码
  6. Android客户端与J2EE服务器的互联
  7. Android跨进程通信
  8. android 解析服务端下发的颜色值
  9. 调用android手机微博客户端发送微博

随机推荐

  1. Android获得当前正在显示的activity类名
  2. Ubuntu 12.04下面设别无法识别android设
  3. Android实现获取SERIAL信息的方法
  4. 计算Android(安卓)App占用的各种空间大小
  5. [置顶] Android系统安全之旅 第1章 运行
  6. android EditText 字数监听并显示
  7. Android中动态设置TextView的drawableLef
  8. QuickContactBadge如何实现
  9. android 有效加载大型Bitmap - 开发文档
  10. android: Looper 源码浅析 [Handler,Loop