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

Android AIDL详解

2016-04-13 16:00 423 查看
转载请注明来自:/article/9320409.html

一、AIDL定义

AIDL(Android Interface Definition Language),它允许你定义客户端与服务端达成一致的程序接口使用进程间通信( interprocess communication ,IPC)相互交流。

在Android上面,一个进程不能正常的访问另一个进程的内存。 所以说,他们需要分解他们的对象为操作系统可以理解的基本单位,然后为你把这些对象按次序跨越进程边界 书写这些代码是单调冗长的,所以android使用AIDL为你处理这个问题。

AIDL IPC机制是面向接口的,它是使用代理类在客户端和实现端传递数据

注意:使用AIDL只有在你允许来自不同应用的客户端跨进程通信访问你的service,并且想要在你的service种处理多线程的时候才是必要的。

二、AIDL接口的创建与使用

你必须在一个.aidl文件中使用java编程语言语法定义你的AIDL接口,然后在提供service的应用中和任何绑定到这个service的应用中的源代码中(在src目录下)保存它

当你编译包含.aidl文件的应用时,Android SDK工具基于这个.aidl文件生成一个IBinder接口,并且把它保存到项目的gen目录吓 service必须恰当的实现这个IBinder接口 之后客户端应用可以绑定到这个服务上,然后从IBinder调用方法来执行IPC

1、创建AIDL文件

IServiceAidlInterface.aidl:

// IServiceAidlInterface.aidl
package com.yang.serviceaidl;

// Declare any non-default types here with import statements

interface IServiceAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,double aDouble, String aString);

void setData(String data);//自定义方法声明
}


默认的,AIDL支持下面数据类型

Java语言中的所有基本数据类型(比如int、long、char、boolean等等)

String

CharSequence

List

List中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是你定义的parcelable
List可以使用范型(例如,List) 接收端的实际类经常是一个ArrayList,尽管方法是使用List接口生成的


Map

Map中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是你定义的parcelable范型map是不被支持的(比如这种形式Map) 接收端的实际类经常是一个HashMap,尽管方法是使用Map接口生成的


对于上述类型之外的类型,你必须声明 import ,即使在同一个包内

简单的保存你的.aidl文件在你工程的src目录下,当你build你的应用时,SDK工具在你工程的gen目录下生成IBinder接口文件 生成的文件名字与.aidl名字匹配,但是是以.java为扩展名(例如IRemoteService.aidl对应为IRemoteService.java)

2、实现接口

在你定义的Service中onBind方法

@Override
public IBinder onBind(Intent intent) {

return new IServiceAidlInterface.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

}

@Override
public void setData(String data) throws RemoteException {
AppService.this.data=data;
}
};
}


Stub类(如IServiceAidlInterface.Stub())是它父类的抽象实现,并且声明了.aidl中所有的方法,

Stub的asInterface()方法,它是用来接收一个IBinder(通常IBinder传递给客户端的onServiceConnected()回调方法)并且返回一个Stub接口的实例。

注意事项:

调用不保证在主线程中执行

默认的,RPC调用是同步的。 如果你知道service需要花费一些时间来完成请求,你就不应该从activity的主线程中调用它,因为它可能使得应用没有响应(Android也许会显示一个ANR的对话框),通常你应该在客户端中一个单独的线程调用它

抛出的异常不会返回给调用者

3、客户端获取接口

如果是跨应用调用Service,那么你应该在另一个应用中一模一样的AIDL文件(包名,类名相同等等),。如下图结构:



在androidapp工程中建立一个与app工程相同的AIDL文件,包括包名。

跨应用启动Service的Intent(显示调用方法);

Intent serviceIntent=new Intent();
serviceIntent.setComponent(new ComponentName("com.yang.serviceaidl","com.yang.serviceaidl.AppService"));

参数说明:

1. 包名
2. 类名

//启动服务   startService(serviceIntent);
//关闭服务  stopService(serviceIntent);
//绑定服务   bindService(serviceIntent,this,Context.BIND_AUTO_CREATE);
//解绑服务    unbindService(this);


在androidapp中调用给接口,在MainActivity(实现了ServiceConnection接口)中onServiceConnected()方法中

private IServiceAidlInterface binder=null;

@Override
public void onServiceConnected(ComponentName name, IBinder service) {

//        binder= (IServiceAidlInterface) service;  //错误的
binder=IServiceAidlInterface.Stub.asInterface(service);
}


类似于Service的绑定通信。

传递数据

if(binder!=null){
try {
binder.setData(data.getText().toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}


总结:调用IPC方法步骤:

在项目中的src目录下面导入.aidl文件

声明一个IBinder接口(基于AIDL生成的)的实例

实现ServiceConnection

调用Context.bindService(),传递到你的ServiceConnection实现中

在你的onServiceConnected()实现中,你会收到一个IBinder实例(称为服务端) 调用YourInterfaceName.Stub.asInterface((IBinder)service)把返回值映射到YourInterface类型上面

调用你接口中定义的方法 你应该捕获当连接损坏时抛出的DeadObjectException异常,这是远程方法唯一会抛出的异常

使用你接口的实例调用Context.unbindService()来断开连接

三、跨进程传递对象

果你想通过IPC接口把一个类从一个进程传递到另一个进程中,那么是可以的。 然而,你必须保证为你的类而写的代码也是对IPC通道另一端是可用的,并且你的类必须支持Parcelable接口 支持Parcelable接口是很重要的,因为它允许Android系统把对象分解为可以被组织跨进程传输基本单元

为了建立一个支持Parcelable协议的类,你必须遵守下面的规则:

要实现Parcelable接口

实现writeToParcel,它是用来把对象的当前状态写入到一个Parcel对象中的。

在你的类中添加一个叫CREATOR的静态域,它要实现Parcelable.Creator接口

最后,建立一个.aidl文件声明你的parcelable类(如下面的Rect.aidl所示)

如果你使用一个定制的构建过程,不要构建.aidl文件。与C语言中的头文件类似,.aidl文件不会被编译

AIDL使用代码中的这些域和方法封装传送和解读你的对象

Rect.aidl文件:

package android.graphics;

// Declare Rect so AIDL can find it and knows that it implements
// the parcelable protocol.
parcelable Rect;


Rect类:

public final class Rect implements Parcelable {
public int left;
public int top;
public int right;
public int bottom;

public static final Parcelable.Creator<Rect> CREATOR = new
Parcelable.Creator<Rect>() {
public Rect createFromParcel(Parcel in) {
return new Rect(in);
}

public Rect[] newArray(int size) {
return new Rect[size];
}
};

public Rect() {
}

private Rect(Parcel in) {
readFromParcel(in);
}

public void writeToParcel(Parcel out) {
out.writeInt(left);
out.writeInt(top);
out.writeInt(right);
out.writeInt(bottom);
}

public void readFromParcel(Parcel in) {
left = in.readInt();
top = in.readInt();
right = in.readInt();
bottom = in.readInt();
}
}


总结

AIDL是android接口定义语言,主要是android中用来解决进程间通信(interprocess communication ,IPC)的。

它和绑定服务通信实现类似,不过是绑定服务通信时我们继承Binder实现的接口MyBinder变成了AIDL实现。

AIDL实例下载链接
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: