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

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

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

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

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

注意,由于客户端和服务端的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(安卓)之 Socket 通信
  2. Android上传文件,客户端+服务器源码
  3. Android(安卓)的网络编程(15)-Http JSon服务器端和客户端通信
  4. unity向android通信
  5. android 软件源码
  6. Android(安卓)博客园客户端 (一) 基本界面
  7. Android跨进程通信
  8. Android客户端与J2EE服务器的互联
  9. android 解析服务端下发的颜色值

随机推荐

  1. 设置Activity为全屏显示的两种方法
  2. [ 转]Android折叠列表 ExpandableList
  3. Android快速开发整理(库、插件、常用网站)
  4. 关于自定义无限轮播图_Android
  5. FFmpeg In Android(安卓)- tutorial-5- S
  6. 关于android AbsSeekBar
  7. Android之Menu动态改变文字
  8. Android(安卓)学习网站
  9. Android(安卓)让一个Service开机自动启动
  10. Android(安卓)检测内存泄漏工具