关于AIDL一些需要注意的地方

时间:2021-05-23 19:02:40

参考:sdk-22.3/docs/guide/components/aidl.html

1、从远程客户端进程来的调用是由不同的线程发起的,运行在不同的进程。所以,服务端必须处理好在同一时刻有多个从不同线程过来的请求的情况。也就是说,一个AIDL的实现必须是完成线程安全的,必须手动处理多线程的情况。

2、AIDL接口当中的oneway关键字代表远程调用的行为。当使用的时候,远程调用不会阻塞,会立即返回。


AIDL中支持的类型:

1、所有的Java基本数据类型,比如int,long,boolean,char,float等。

2、String

3、CharSequence

4、List,List当中的数据元素必须能够被AIDL支持

5、Map:只支持HashMap,里面的每个元素都必须被AIDL支持,包括key和value

6、Parcelable:实现了Parcelable接口的对象

7、AIDL接口:所有的AIDL接口本身也可以在AIDL文件中使用。


其中自定义的Parcelable对象和AIDL对象必须要显式的import进来,不管这些对象是否和当前的AIDL是否是在同一个包中。如下所示,IRemoteService和IRemoteServiceCallback在同一个包当中。

关于AIDL一些需要注意的地方

然后在IRemoteService 当中使用了IRemoteServiceCallback接口,就需要把IRemoteServiceCallback  import进来,不然会报错,代码如下所示:

/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.easyliu.demo.aidl;

import com.easyliu.demo.aidl.IRemoteServiceCallback;
/**
* Example of defining an interface for calling on to a remote service
* (running in another process).
*/
interface IRemoteService {
/**
* Often you want to allow a service to call back to its clients.
* This shows how to do so, by registering a callback interface with
* the service.
*/
void registerCallback(IRemoteServiceCallback cb);

/**
* Remove a previously registered callback interface.
*/
void unregisterCallback(IRemoteServiceCallback cb);
}

当定义服务AIDL接口的时候,有几点需要注意

1、方法可能有零个或者多个输入参数,可以返回一个值或返回空

2、AIDL中除了基本数据类型参数,其他类型的参数必须标上方向:in、out或者inout。基本类型默认就是in,不能是其他。

3、AIDL文件当中的注释将会包括在产生的.java文件当中,除了在import和包名前面的注释。

4、AIDL中只支持方法,不支持静态常量。


通过IPC传递对象

如果你有一个类需要跨进程进行传输,你必须保证这个类实现了Parcelable接口并且在IPC的另外一端也有这个类。

为了创建一个支持Parcelable协议的类,必须做下面工作:

1、保证你的类实现Parcelable接口

2、实现writeToParcel方法,这个方法将得到当前对象的状态,然后写入Parcel

3、给类增加一个叫做CREATOR的静态常量,这个静态常量实现了Parcelable.Creator接口

AIDL使用以上这些方法和域实现对象的序列化和反序列化

4、最后,如果在AIDL中用到了这个自定义的类,那么必须创建一个和它同名的.aidl文件,并在其中这个类为Parcelable类型,如下所示,创建了一个Rect.aidl文件,在这个文件中声明了Rect为Parcelable类型。

// Rect.aidl
package com.easyliu.demo.aidlremotedemo;
parcelable Rect;

下面是Rect类的具体实现:

package com.easyliu.demo.aidlremotedemo;

/**
* Created by LiuYi on 2016/6/19.
*/

import android.os.Parcel;
import android.os.Parcelable;

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];
}
};

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

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

@Override
public int describeContents() {
return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(left);
dest.writeInt(top);
dest.writeInt(right);
dest.writeInt(bottom);
}
}


使用Rect的方式如下所示:有一个AIDL接口IRectManager,里面使用了Rect对象,需要把Rect给import进来,在addRect方法的参数中,标注了参数的方向:in。

// IRectManager.aidl
package com.easyliu.demo.aidlremotedemo;
import com.easyliu.demo.aidlremotedemo.Rect;
interface IRectManager {
List<Rect> getRectList();
void addRect(in Rect rect);
}


最好是把AIDL相关的类和文件都放到一个包里面,这样就可以直接在客户端和服务端进行移植,如下所示:

关于AIDL一些需要注意的地方