【Android】使用AIDL传递用户自定义类型数据--附完整示例代码

AIDL对Java类型的支持

  1. AIDL支持Java原始数据类型
  2. AIDL支持String和CharSequence
  3. AIDL支持传递其他AIDL接口,但你引用的每个AIDL接口都需要一个import语句,即使位于同一个包中
  4. AIDL支持传递实现了android.os.Parcelable接口的复杂类型,同样在引用这些类型时也需要import语句
  5. AIDL支持java.util.List和java.util.Map,但是有一些限制。集合中项的允许数据类型包括Java原始类型、String、CharSequence或是android.os.Parcelable。无需为List和Map提供import语句,但需要为Parcelable提供import语句
  6. 非原始类型中,除了String和CharSequence以外,其余均需要一个方向指示符。方向指示符包括in、out、和inout。in表示由客户端设置,out表示由服务端设置,inout表示客户端和服务端都设置了该值

增加的内容

AIDL传递复杂类型对象的特殊处理。前面已经介绍了通过AIDL接口在进程间传递系统允许的数据,如果需要传递一个复杂类型的对象,需要额外做一些处理。如下:
1. 定义数据接口的AIDL文件中,使用parcelable关键字,例如:parcelable Person
2. 在其数据实现类中实现Parcelable接口,并实现对应的方法
3. 在业务接口的AIDL文件中,使用import引入数据接口AIDL的包名

Person.java是实现了parcelable的类型,Person.aidl是其数据接口aidl文件,IPerson.aidl文件是其业务接口aidl文件。还需要注意一点的是aidl文件的接口名需要和其文件名保持一致。

定义一个自定义数据类型并定义该数据接口的AIDL文件

这一步很容易被忽略,因为我们平时使用的Bean或者其他数据类型都不会单独去定义一个数据接口。如果这一步忘记的话,将会出现
couldn't find import for class
的错误。

定义了Person之后,添加该类型的AIDL如下:Person.aidl


    package com.example.aidl;

    parcelable Person;

实现该类型的Parcelable接口并添加一个静态CREATOR

Person的静态数据成员CREATOR:

此静态属性,则是为了反编译时使用,在Parcelable进行反编译时将会调用该属性,所以名称写法基本是固定不变的。由于其中重载的第二个函数使用了赋值构造,所以在自定义数据类型中还需要一个赋值构造函数。当然如果不重载该函数也就不需要赋值构造了。


    public static final Parcelable.Creator<Person> CREATOR = new Creator<Person>() {

        @Override
        public Person[] newArray(int size) {
            return new Person[size];
        }

        @Override
        public Person createFromParcel(Parcel source) {
            return new Person(source);
        }
    };

需要重载的函数writeToParcel(),根据自己定义的实际情况来写,这里的Person使用了一个String成员变量,一个int 和一个float[]。具体的写入操作,一定需要注意的是写入顺序则决定了读取顺序


    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(age);
        dest.writeString(name);
        if (scores != null) {
            dest.writeInt(scores.length);
            dest.writeFloatArray(scores);
        } else {
            dest.writeInt(0);
        }
    }

关于两种序列化的对比和区别

(Parcelable接口告诉Android运行时在封送(marshalling)和解封送(unmarshalling)过程中实现如何序列化和反序列化对象,你可以很容易联想到java.io.Serializable接口。有些朋友可能会有疑问,两种接口功能确实类似,但为什么Android不用内置的Java序列化机制,而偏偏要搞一套新东西呢?这是因为Android团队认为Java中的序列化太慢,难以满足Android的进程间通信需求,所以他们构建了Parcelable解决方案。Parcelable要求显示序列化类的成员,但最终序列化对象的速度将快很多。另外要注意的是,Android提供了两种机制来将数据传递给另一个进程,第一种是使用Intent将数据束(Bundle)传递给活动,第二种也就是Parcelable传递给服务。这两种机制不可互换,不要混淆。也就是说,Parcelable无法传递给活动,只能用作AIDL定义的一部分)。

定义业务类型的AIDL文件

业务类型的AIDL和之前一样,定义其中的方法,并且在Client和Service中保留一份,然后就可以使用了。

注意一点的是需要导包,也就是下面的第二行


    package com.example.aidl;
    import com.example.aidl.Person;
    interface IPerson{
        Person getPerson();
    }

使用该AIDL进行通信和方法调用

该过程和基本数据类型的通信过程一模一样,只要在上述定义自定义类型处实现了数据接口的AIDL和业务类型的AIDL,那么按之前的一篇博文中所将的步骤(此时自定义的类型已经可以当做是基本类型被支持了),依次实现服务端和客户端的内容即可。
步骤依然是服务端的Service中的onBind()方法的重载和Manifest文件中的service的配置。客户端的Intent和ServiceConnection。具体可以看最下方源码链接中的实现。

执行结果

默认构造了一个Person对象,zhangsan ,年龄20,以及三门课程的成绩。

源代码及参考链接

最近的两篇博文中的文件目录和全部的代码都在里面,可以参考一下。里面的Log写的不规范,代码也很乱,欢迎提出意见,哈哈……

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

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

参考链接:
http://blog.csdn.net/liuhe688/article/details/6409708
http://www.android100.org/html/201507/13/164469.html
http://www.2cto.com/kf/201507/419263.html

你可能感兴趣的:(android,数据,rmi,ipc,aidl)