Android(安卓)AIDL(Android(安卓)Interface Definition Language)介绍
在网上看到一篇介绍AIDL的文章,自己把代码在2.2的sdk上跑了一下,稍微更改了一下原文中的代码(下文中的代码都是自己编译通过后使用的代码)并且添加了xml文件,大家可以按照这个代码自己实现一遍。
以下部门来自网上其他朋友的文章(由于出处太多,无法找到原始的地址)
================================================================
在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.android.aidltest;
- importcom.android.aidltest.ITaskCallback;
- interfaceITaskBinder{
- booleanisTaskRunning();
- voidstopRunningTask();
- voidregisterCallback(ITaskCallbackcb);
- voidunregisterCallback(ITaskCallbackcb);
- }
其中: ITaskCallback在文件ITaskCallback.aidl中定义:
- packagecom.android.aidltest;
- interfaceITaskCallback{
- voidactionPerformed(intactionId);
- }
注意:理论上,参数可以传递基本数据类型和String,还有就是Bundle的派生类,不过在Eclipse中,目前的ADT不支持Bundle做为参数,据说用Ant编译可以,我没做尝试.
2、编译AIDL文件,用Ant的话,可能需要手动,使用Eclipse plugin的话,可以根据adil文件自动生产java文件并编译,不需要人为介入.
3、在Java文件中,实现AIDL中定义的接口.编译器会根据AIDL接口,产生一个JAVA接口。这个接口有一个名为Stub的内部抽象类,它继承扩展了接口并实现了远程调用需要的几个方法。接下来就需要自己去实现自定义的几个接口了.
ITaskBinder.aidl中接口的实现,在MyService.java中接口以内嵌类的方式实现:
- privatefinalITaskBinder.StubmBinder=newITaskBinder.Stub(){
- @Override
- publicvoidunregisterCallback(ITaskCallbackcb)throwsRemoteException{
- printf("serviceonunregisterCallback");
- //TODOAuto-generatedmethodstub
- if(cb!=null)
- mCallbacks.unregister(cb);
- }
- @Override
- publicvoidstopRunningTask()throwsRemoteException{
- printf("serviceonstopRunningTask");
- //TODOAuto-generatedmethodstub
- }
- @Override
- publicvoidregisterCallback(ITaskCallbackcb)throwsRemoteException{
- printf("serviceonregisterCallback");
- //TODOAuto-generatedmethodstub
- if(cb!=null)
- mCallbacks.register(cb);
- }
- @Override
- publicbooleanisTaskRunning()throwsRemoteException{
- printf("serviceonisTaskRunning");
- //TODOAuto-generatedmethodstub
- returnfalse;
- }
- };
在aidltest.java中ITaskCallback.aidl接口实现:
- privateITaskCallbackmCallback=newITaskCallback.Stub(){
- @Override
- publicvoidactionPerformed(intactionId)throwsRemoteException{
- //TODOAuto-generatedmethodstub
- printf("callbackid="+actionId);
- }
- };
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<N;i++){
- try{
- mCallbacks.getBroadcastItem(i).actionPerformed(val);
- }catch(RemoteExceptione){
- }
- }
- mCallbacks.finishBroadcast();
- }
AIDL的创建方法:
AIDL语法很简单,可以用来声明一个带一个或多个方法的接口,也可以传递参数和返回值。 由于远程调用的需要,这些参数和返回值并不是任何类型.下面是些AIDL支持的数据类型:
1.不需要import声明的简单Java编程语言类型(int,boolean等)
2. String, CharSequence不需要特殊声明
3. List, Map和Parcelables类型, 这些类型内所包含的数据成员也只能是简单数据类型, String等其他比支持的类型.
(另外: 我没尝试Parcelables, 在Eclipse+ADT下编译不过, 或许以后会有所支持).
实现接口时有几个原则:
.抛出的异常不要返回给调用者. 跨进程抛异常处理是不可取的.
.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.android.aidltest;
- interfaceITaskCallback{
- voidactionPerformed(intactionId);
- }
2. ITaskBinder.aidl
- packagecom.android.aidltest;
- importcom.android.aidltest.ITaskCallback;
- interfaceITaskBinder{
- booleanisTaskRunning();
- voidstopRunningTask();
- voidregisterCallback(ITaskCallbackcb);
- voidunregisterCallback(ITaskCallbackcb);
- }
3.MyService.java
- packagecom.android.aidltest;
- importandroid.app.Service;
- importandroid.content.Intent;
- importandroid.os.IBinder;
- importandroid.os.RemoteCallbackList;
- importandroid.os.RemoteException;
- importandroid.util.Log;
- publicclassMyServiceextendsService{
- publicvoidonCreate(){
- printf("servicecreate");
- }
- publicvoidonStart(Intentintent,intstartId){
- printf("servicestartid="+startId);
- callback(startId);
- }
- @Override
- publicIBinderonBind(Intentintent){
- //TODOAuto-generatedmethodstub
- printf("serviceonbind");
- returnmBinder;
- }
- publicvoidonDestroy(){
- printf("serviceondestroy");
- super.onDestroy();
- }
- 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<N;i++){
- try{
- mCallbacks.getBroadcastItem(i).actionPerformed(val);
- }catch(RemoteExceptione){
- }
- }
- mCallbacks.finishBroadcast();
- }
- privatefinalITaskBinder.StubmBinder=newITaskBinder.Stub(){
- @Override
- publicvoidunregisterCallback(ITaskCallbackcb)throwsRemoteException{
- printf("serviceonunregisterCallback");
- //TODOAuto-generatedmethodstub
- if(cb!=null)
- mCallbacks.unregister(cb);
- }
- @Override
- publicvoidstopRunningTask()throwsRemoteException{
- printf("serviceonstopRunningTask");
- //TODOAuto-generatedmethodstub
- }
- @Override
- publicvoidregisterCallback(ITaskCallbackcb)throwsRemoteException{
- printf("serviceonregisterCallback");
- //TODOAuto-generatedmethodstub
- if(cb!=null)
- mCallbacks.register(cb);
- }
- @Override
- publicbooleanisTaskRunning()throwsRemoteException{
- printf("serviceonisTaskRunning");
- //TODOAuto-generatedmethodstub
- returnfalse;
- }
- };
- finalRemoteCallbackList<ITaskCallback>mCallbacks
- =newRemoteCallbackList<ITaskCallback>();
- }
4. aidltest.java
- packagecom.android.aidltest;
- 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;
- publicclassAidlTestextendsActivity{
- privateButtonbtnOk;
- privateButtonbtnCancel;
- /**Calledwhentheactivityisfirstcreated.*/
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- btnOk=(Button)findViewById(R.id.btn_ok);
- btnCancel=(Button)findViewById(R.id.btn_cancel);
- btnOk.setText("StartService");
- btnCancel.setText("StopService");
- btnOk.setOnClickListener(newOnClickListener(){
- publicvoidonClick(Viewv){
- onOkClick();
- }
- });
- btnCancel.setOnClickListener(newOnClickListener(){
- publicvoidonClick(Viewv){
- onCancelClick();
- }
- });
- }
- voidonOkClick(){
- printf("clickedok");
- Bundleargs=newBundle();
- Intentintent=newIntent(this,MyService.class);
- intent.putExtras(args);
- bindService(intent,mConnection,Context.BIND_AUTO_CREATE);
- startService(intent);
- }
- voidonCancelClick(){
- printf("clickedcancel");
- Intentintent=newIntent(this,MyService.class);
- unbindService(mConnection);
- }
- privatevoidprintf(Stringstr){
- Log.e("TAG","##################-------"+str+"-----");
- }
- ITaskBindermService;
- privateServiceConnectionmConnection=newServiceConnection(){
- publicvoidonServiceConnected(ComponentNameclassName,
- IBinderservice){
- mService=ITaskBinder.Stub.asInterface(service);
- try{
- mService.registerCallback(mCallback);
- }catch(RemoteExceptione){
- }
- }
- publicvoidonServiceDisconnected(ComponentNameclassName){
- mService=null;
- }
- };
- privateITaskCallbackmCallback=newITaskCallback.Stub(){
- @Override
- publicvoidactionPerformed(intactionId)throwsRemoteException{
- //TODOAuto-generatedmethodstub
- printf("callbackid="+actionId);
- }
- };
- }
5. xml文件
AndroidMenifest.xml
- <?xmlversion="1.0"encoding="utf-8"?>
- <manifestxmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.aidltest"
- android:versionCode="1"
- android:versionName="1.0">
- <applicationandroid:icon="@drawable/icon"android:label="@string/app_name">
- <activityandroid:name=".AidlTest"
- android:label="@string/app_name">
- <intent-filter>
- <actionandroid:name="android.intent.action.MAIN"/>
- <categoryandroid:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
- <serviceandroid:name=".MyService">
- <intent-filter>
- <actionandroid:name="com.android.aidltest.START_MYSERVICE"/>
- <categoryandroid:name="android.intent.category.DEFAULT"/>
- </intent-filter>
- </service>
- </application>
- <uses-sdkandroid:minSdkVersion="8"/>
- </manifest>
main.xml
- <?xmlversion="1.0"encoding="utf-8"?>
- <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <TextView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="@string/hello"
- />
- <Button
- android:id="@+id/btn_ok"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/btn_ok"
- />
- <Button
- android:id="@+id/btn_cancel"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/btn_cancel"
- />
- </LinearLayout>
string.xml
- <?xmlversion="1.0"encoding="utf-8"?>
- <resources>
- <stringname="hello">HelloWorld,AidlTest!</string>
- <stringname="app_name">AIDLTest</string>
- <stringname="btn_ok">OK</string>
- <stringname="btn_cancel">Cancel</string>
- </resources>
更多相关文章
- android目录结构介绍(寒假学习1)
- 百度地图开发-申请ak及相关配置
- 《Android(安卓)安全(一)》AndroidManifest.xml之allowBackup属性
- unity与android交互(1)
- [转]Android(安卓)xmlns 的作用及其自定义
- Android的ADT不能自动生成R.java
- Android资源文件Res详解——ShapeDrawable
- Android日记之2012\01\15
- 手动编译android项目