AIDLAndroid中的远程接口调用RPC.docx
- 文档编号:7269851
- 上传时间:2023-01-22
- 格式:DOCX
- 页数:13
- 大小:49.93KB
AIDLAndroid中的远程接口调用RPC.docx
《AIDLAndroid中的远程接口调用RPC.docx》由会员分享,可在线阅读,更多相关《AIDLAndroid中的远程接口调用RPC.docx(13页珍藏版)》请在冰豆网上搜索。
AIDLAndroid中的远程接口调用RPC
远程过程调用
Android拥有轻量级的远程调用机制(RPC)—方法在本地调用,在远程执行(在其它进程中),结果返回给调用者。
这意味着将方法调用及其附带的数据分解为操作系统可以理解的形式,将其由本地进程和地址空间传送到远程进程和地址空间中,在远程重新装配并执行该调用。
返回值沿着相反的方向传递。
Android提供了实现该机制的所有代码,因此你只需要关注于如何定义和实现该RPC接口本身。
RPC接口只能包含方法。
所有的方法都是同步执行的(本地方法被阻断,直到远程方法结束),即使没有返回值。
简而言之,该机制的流程如下:
你由使用简单的IDL(接口定义语言)定义要实现的RPC接口。
根据接口的定义,aidl工具生成本地和远程进程必要的Java接口的定义。
它包含下图所示的两个内部类:
内部类中包含管理你用IDL生成的远程过程调用需要的所有代码。
两个内部类都实现了IBinder接口。
其中一个在本地由系统内部使用,写代码时可以忽略它。
另一个叫做Stub,扩展自Binder类。
作为对执行IPC调用的内部代码补充,它包含你在RPC接口中声明的方法。
象图中说明的那样,你应该继承Stub来实现这些方法。
一般远程过程由服务来管理(因为服务可以通知系统关于进程和它连接的其它进程的信息)。
它既有aidl。
服务的客户端只有由aidl生成的接口文件。
接下来是服务和其客户端是如何建立连接的:
服务的客户端(为位于本地)应该实现onServiceConnected()和onServiceDisconnected()方法,这样它们就可以在成功与远程服务建立或断开连接后收到消息。
它们应该调用bindService()来设置连接。
服务的onBind()方法应该被实现用作根据收到的意图(传入bindService()的意图),决定接受或拒绝连接。
如果连接被接受,它返回一个Stub的子类。
如果服务接受了连接,Android调用客户端的onServiceConnected()方法并传入一个IBinder对象,由服务管理的Stub子类的代理。
通过该代理,客户端可以调用远程服务。
上述简单的描述忽略了一些RPC机制的细节。
更多信息参见用AIDL设计远程接口和IBinder类的描述。
在Android中,每个应用程序都可以有自己的进程.在写UI应用的时候,经常要用到Service.在不同的进程中,怎样传递对象呢?
显然,Java中不允许跨进程内存共享.因此传递对象,只能把对象拆分成操作系统能理解的简单形式,以达到跨界对象访问的目的.在J2EE中,采用RMI的方式,可以通过序列化传递对象.在Android中,则采用AIDL的方式.理论上AIDL可以传递Bundle,实际上做起来却比较麻烦.
AIDL(AndRoid接口描述语言)是一种借口描述语言;编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程的目的.如果需要在一个Activity中,访问另一个Service中的某个对象,需要先将对象转化成AIDL可识别的参数(可能是多个参数),然后使用AIDL来传递这些参数,在消息的接收端,使用这些参数组装成自己需要的对象.
AIDL的IPC的机制和COM或CORBA类似,是基于接口的,但它是轻量级的。
它使用代理类在客户端和实现层间传递值.如果要使用AIDL,需要完成2件事情:
1.引入AIDL的相关类.;2.调用aidl产生的class.
具体实现步骤如下:
1、创建AIDL文件,在这个文件里面定义接口,该接口定义了可供客户端访问的方法和属性。
如:
ITaskBinder.adil
packagecom.cmcc.demo;
importcom.cmcc.demo.ITaskCallback;
interfaceITaskBinder{
booleanisTaskRunning();
voidstopRunningTask();
voidregisterCallback(ITaskCallbackcb);
voidunregisterCallback(ITaskCallbackcb);
}
其中:
ITaskCallback在文件ITaskCallback.aidl中定义:
packagecom.cmcc.demo;
interfaceITaskCallback{
voidactionPerformed(intactionId);
}
注意:
理论上,参数可以传递基本数据类型和String,还有就是Bundle的派生类,不过在Eclipse中,目前的ADT不支持Bundle做为参数,据说用Ant编译可以,我没做尝试.
2、编译AIDL文件,用Ant的话,可能需要手动,使用Eclipseplugin的话,可以根据adil文件自动生产java文件并编译,不需要人为介入.
3、在Java文件中,实现AIDL中定义的接口.编译器会根据AIDL接口,产生一个JAVA接口。
这个接口有一个名为Stub的内部抽象类,它继承扩展了接口并实现了远程调用需要的几个方法。
接下来就需要自己去实现自定义的几个接口了.
ITaskBinder.aidl中接口的实现,在MyService.java中接口以内嵌类的方式实现:
privatefinalITaskBinder.StubmBinder=newITaskBinder.Stub(){
publicvoidstopRunningTask(){
//@TODO
}
publicbooleanisTaskRunning(){
//@TODO
returnfalse;
}
publicvoidregisterCallback(ITaskCallbackcb){
if(cb!
=null)mCallbacks.register(cb);
}
publicvoidunregisterCallback(ITaskCallbackcb){
if(cb!
=null)mCallbacks.unregister(cb);
}
};
在MyActivity.java中ITaskCallback.aidl接口实现:
privateITaskCallbackmCallback=newITaskCallback.Stub(){
publicvoidactionPerformed(intid){
//TODO
printf("callbackid="+id);
}
};
4、向客户端提供接口ITaskBinder,如果写的是service,扩展该Service并重载onBind()方法来返回一个实现上述接口的类的实例。
这个地方返回的mBinder,就是上面通过内嵌了定义的那个.(MyService.java)
publicIBinderonBind(Intentt){
printf("serviceonbind");
returnmBinder;
}
在Activity中,可以通过Binder定义的接口,来进行远程调用.
5、在服务器端回调客户端的函数.前提是当客户端获取的IBinder接口的时候,要去注册回调函数,只有这样,服务器端才知道该调用那些函数在:
MyService.java中:
voidcallback(intval){
finalintN=mCallbacks.beginBroadcast();
for(inti=0;i try{ mCallbacks.getBroadcastItem(i).actionPerformed(val); }catch(RemoteExceptione){ //TheRemoteCallbackListwilltakecareofremoving //thedeadobjectforus. } } mCallbacks.finishBroadcast(); } AIDL的创建方法: AIDL语法很简单,可以用来声明一个带一个或多个方法的接口,也可以传递参数和返回值。 由于远程调用的需要,这些参数和返回值并不是任何类型.下面是些AIDL支持的数据类型: 1.不需要import声明的简单Java编程语言类型(int,boolean等) 2.String,CharSequence不需要特殊声明 3.List,Map和Parcelables类型,这些类型内所包含的数据成员也只能是简单数据类型,String等其他比支持的类型. ( (另外: 我没尝试Parcelables,在Eclipse+ADT下编译不过,或许以后会有所支持). 下面是AIDL语法: //文件名: SomeClass.aidl //文件可以有注释,跟java的一样 //在package以前的注释,将会被忽略. //函数和变量以前的注释,都会被加入到生产java代码中. packagecom.cmcc.demo; //import引入语句 importcom.cmcc.demo.ITaskCallback; interfaceITaskBinder{ //函数跟java一样,可以有0到多个参数,可以有一个返回值 booleanisTaskRunning(); voidstopRunningTask(); //参数可以是另外的一个aidl定义的接口 voidregisterCallback(ITaskCallbackcb); voidunregisterCallback(ITaskCallbackcb); //参数可以是String,可以用in表入输入类型,out表示输出类型. intgetCustomerList(inStringbranch,outString[]customerList); } 实现接口时有几个原则: .抛出的异常不要返回给调用者.跨进程抛异常处理是不可取的. .IPC调用是同步的。 如果你知道一个IPC服务需要超过几毫秒的时间才能完成地话,你应该避免在Activity的主线程中调用。 也就是IPC调用会挂起应用程序导致界面失去响应.这种情况应该考虑单起一个线程来处理. .不能在AIDL接口中声明静态属性。 IPC的调用步骤: 1.声明一个接口类型的变量,该接口类型在.aidl文件中定义。 2.实现ServiceConnection。 3.调用ApplicationContext.bindService(),并在ServiceConnection实现中进行传递. 4.在ServiceConnection.onServiceConnected()实现中,你会接收一个IBinder实例(被调用的Service).调用 YourInterfaceName.Stub.asInterface((IBinder)service)将参数转换为YourInterface类型。 5.调用接口中定义的方法。 你总要检测到DeadObjectException异常,该异常在连接断开时被抛出。 它只会被远程方法抛出。 6.断开连接,调用接口实例中的ApplicationContext.unbindService() 下面是整个程序: 1.ITaskCallback.aidl packagecom.cmcc.demo; interfaceITaskCallback{ voidactionPerformed(intactionId); } 2.ITaskBinder.aidl packagecom.cmcc.demo; importcom.cmcc.demo.ITaskCallback; interfaceITaskBinder{ booleanisTaskRunning(); voidstopRunningTask(); voidregisterCallback(ITaskCallbackcb); voidunregisterCallback(ITaskCallbackcb); } 3. MyService.java packagecom.cmcc.demo; importandroid.app.Service; importandroid.content.Intent; importandroid.os.IBinder; importandroid.os.RemoteCallbackList; importandroid.os.RemoteException; importandroid.util.Log; publicclassMyServiceextendsService{ @Override publicvoidonCreate(){ printf("servicecreate"); } @Override publicvoidonStart(Intentintent,intstartId){ printf("servicestartid="+startId); callback(startId); } @Override publicIBinderonBind(Intentt){ printf("serviceonbind"); returnmBinder; } @Override publicvoidonDestroy(){ printf("serviceondestroy"); super.onDestroy(); } @Override publicbooleanonUnbind(Intentintent){ printf("serviceonunbind"); returnsuper.onUnbind(intent); } publicvoidonRebind(Intentintent){ printf("serviceonrebind"); super.onRebind(intent); } privatevoidprintf(Stringstr){ Log.e("TAG","###################------"+str+"------"); } voidcallback(intval){ finalintN=mCallbacks.beginBroadcast(); for(inti=0;i try{ mCallbacks.getBroadcastItem(i).actionPerformed(val); }catch(RemoteExceptione){ //TheRemoteCallbackListwilltakecareofremoving //thedeadobjectforus. } } mCallbacks.finishBroadcast(); } privatefinalITaskBinder.StubmBinder=newITaskBinder.Stub(){ publicvoidstopRunningTask(){ } publicbooleanisTaskRunning(){ returnfalse; } publicvoidregisterCallback(ITaskCallbackcb){ if(cb! =null)mCallbacks.register(cb); } publicvoidunregisterCallback(ITaskCallbackcb){ if(cb! =null)mCallbacks.unregister(cb); } }; finalRemoteCallbackList =newRemoteCallbackList } 4.MyActivity.java packagecom.cmcc.demo; importandroid.app.Activity; importandroid.content.ComponentName; importandroid.content.Context; importandroid.content.Intent; importandroid.content.ServiceConnection; importandroid.graphics.Color; importandroid.os.Bundle; importandroid.os.IBinder; importandroid.os.RemoteException; importandroid.util.Log; importandroid.view.View; importandroid.view.ViewGroup; importandroid.view.View.OnClickListener; importandroid.widget.AbsoluteLayout; importandroid.widget.Button; importandroid.widget.LinearLayout; importandroid.widget.RelativeLayout; importandroid.widget.TextView; importjava.io.BufferedReader; importjava.io.File; importjava.io.FileOutputStream; importjava.io.FileReader; importjava.io.PrintWriter; publicclassMyActivityextendsActivity{ privateButtonbtnOk; privateButtonbtnCancel; @Override publicvoidonCreate(Bundleicicle){ super.onCreate(icicle); setContentView(R.layout.test_service); btnOk=(Button)findViewById(R.id.btn_ok); btnCancel=(Button)findViewById(R.id.btn_cancel); btnOk.setText("StartService"); btnCancel.setTag("StopService"); btnOk.setOnClickListener(newOnClickListener(){ publicvoidonClick(Viewv){ onOkClick(); } }); btnCancel.setOnClickListener(newOnClickListener(){ publicvoidonClick(Viewv){ onCancelClick(); } }); } voidonOkClick(){ Bundleargs=newBundle(); Intentintent=newIntent(this,MyService.class); intent.putExtras(args); //printf("sendintenttostart"); //startService(intent); bindService(intent,mConnection,Context.BIND_AUTO_CREA
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- AIDL Android中的远程接口调用RPC Android 中的 远程 接口 调用 RPC