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

参考: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一些需要注意的地方_第1张图片

然后在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 CREATOR = new
            Parcelable.Creator() {
                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 getRectList();
   void addRect(in Rect rect);
}


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

关于AIDL一些需要注意的地方_第2张图片



你可能感兴趣的:(Android进阶)