您的位置:首页 > 移动开发 > Android开发

【Android】AIDL原理以及基本类型数据传递

2015-10-24 11:50 686 查看

AIDL原理

AIDL是 Android Interface definition language的缩写,它是一种进程通信接口的描述,通过sdk解释器对器进行编译,会把它编译成java代码在gen目录下,类路径与aidl文件的类路径相同。

AIDL的目的就是让 IPC的通讯就像调用函数那样简单。自动的帮你完成了参数序列化发送以及解析返回数据的那一系列麻烦。而你所需要做的就是写上一个接口文件,然后利用aidl工具转化一下得到另一个java文件,这个文件在服务和客户端程序各放一份。服务程序继承IxxxxService.Stub 然后将函数接口里面的逻辑代码实现一下,而客户端通过服务绑定获取服务端返回的Stub,就可以通过这个Stub像是调用本地方法一样调用远程方法并进行进程间的通信了。基本原理大概就是这样,如果深入理解的话可以看看Java中的远程过程调用RMI和Unix网络编程的第二卷专门讲IPC。

客户端和服务端进行通讯,你得先将你的通讯请求转换成序列化的数据,然后调用函数发送给服务端,而且还得制定一个协议,参数谁先谁后,服务端和客户端都必须一致,否则就会出错。这样的过程很麻烦,如果有上百个接口,那可就要疯掉了。而AIDL就很好的解决上述的一系列问题,规范化了远程调用和数据传输,只需要写一个aidl文件定义一个服务函数,这份AIDL文件同时放到client 和Service端,由IDE生成响应的java文件。生成的java文件的UML图如下,Client通过本地代理调用远程方法,远程服务为Client提供一个Stub存根供其使用。本质上Client和Service并不是直接联系的,stub存根抽像类需要在服务端实现,proxy代理类被客户端使用,通过stub,proxy的封装,屏蔽了进程通信的细节。



AIDL跨进程传递基本类型数据

对于基本数据类型如String ,int, float 等可以直接在进程间传递,所需要做的就是定义好接口文件。工程结构如下:

客户端:



服务端:



完整过程如下:

第一步:定义AIDL接口

AIDL接口文件在客户端和服务器端都要定义,并且要在同一包中,就是上图中的StringServiceAIDL.aidl文件。该文件定义完成之后,IDE会自动为我们生成同名java文件,此处为StringServiceAIDL.java。不用去管其中的细节,也不需要纠结其中的内容,只要生成就可以使用了。

aild文件内容如下:

package com.example.aidl;

interface StringServiceAIDL{
String getString();
}


第二步:实现服务端的Service类

该类继承Service,就是这里的StringService类,只需要重载其中的OnBind()方法就可以了,然后定义一个存根stub,并在服务绑定的时候通过OnBind()中将该存根返回。这里的service端实现了getString()方法,仅仅是返回了一个字符串。

public class StringService extends Service {

StringServiceAIDL.Stub stub = new StringServiceAIDL.Stub() {

@Override
public String getString() throws RemoteException {
return "StringService : hello AIDL from a remote thread";
}
};

@Override
public IBinder onBind(Intent arg0) {
return stub;
}

}


第三步:服务端配置文件设置

在Service端还需要配置一个服务,设置其开启的过滤事件以便于在Client端进行服务开启

AndroidManifest.xml文件添加如下:

<service android:name=".StringService" >
<intent-filter>
<action android:name="com.example.aidl.StringServiceAIDL.STRINGSERVICE" />
</intent-filter>
</service>


第四步:在Client端进行服务绑定

Service端的服务实现之后就可以在Client端进行调用了,调用钱需要绑定服务bindService(),该方法需要三个参数,一个Intent,一个ServiceConnection。Intent就是我们将要开启的服务,ServiceConnection是一个连接服务,通过其中的onServiceConnected()获取远程对象以进行方法调用。

Intent的实现就和普通的服务开启时一样的,只是在启动的时候需要制定一个action,用来进行意图过滤开启制定的服务.开启方法不唯一,如下示例:

intent = new Intent();
intent.setAction(action);
Log.i(TAG, " ---- start service ---- ");
startService(intent);
Log.i(TAG, " ---- bind service ---- ");
bindService(intent, conn, BIND_AUTO_CREATE);


ServiceConnection的实现代码如下,在服务绑定的时候调用,重载其onServiceConnected()方法,其中最主要的一句是

strService = StringServiceAIDL.Stub.asInterface(arg1);


这行代码将一个IBinder对象转换为一个接口,通过该接口就可以实现远程通信和调用。

private ServiceConnection strConn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName arg0) {
Log.i(TAG, "onServiceDisconnected()");
}

@Override
public void onServiceConnected(ComponentName arg0, IBinder arg1) {
Log.i(TAG, "onServiceConnected()");
strService = StringServiceAIDL.Stub.asInterface(arg1);
try {
handleMsg(strService.getString());
} catch (RemoteException e) {
handleMsg("RemoteException onServiceConnected()");
e.printStackTrace();
}
}
};


测试结果

分别部署上述的Client和Service到模拟器,Service端没有数据输出,Client端会输出Service给定的字符串数据,由于没有关心服务绑定开启的细节,所以程序执行的时候回直接输出该字符串,但是会有Log输出,便于查看执行流程。

Service先部署,执行如下:输出了一个界面,作为一个服务也可以不生成activity,但是作为测试通过界面观察直观一些



然后部署Client,执行结果如下:

点击AIDLSimple Data Test就可以看到传递的基本String类型数据。这个Demo同时实现了基本数据类型和自定义数据类型的传递。回调暂时没有实现,后面会补上。



源码及参考链接

完整的实现代码在github上,可以直接查看或者clone到本地执行

Client:

https://github.com/zp-zone/AIDLClient

Service:

https://github.com/zp-zone/AIDLService

参考链接:

http://www.cnblogs.com/BeyondAnyTime/p/3204119.html

http://blog.csdn.net/liuhe688/article/details/6400385
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  AIDL RMI IPC android java