android的AIDL

一.AIDL的意义:

             AIDL全称是Android Interface Definition Language,是android接口定义语言。AIDL就是为了避免我们一遍遍的写一些千篇一律的代码而出现的一个模板。

                目的:实现进程间通信,而且在能在多进程并发的情况下进行进程间的通信。

                与Messenger的区别: Messenger 是以串行的方式处理客户端发来的消息,如果有大量的并发请求那么Messenger就不大适合这些情况了,同时Messenger的作用主要是为了传递消息,很多的时候我们可能需要跨进程调用服务端的方法,这种情形用Messenger就无法做到了,但是AIDL可以。AIDL也是Messenger的底层实现,因此Messenger的本质也是AIDL,只不过系统为我们做了封装方便上层的调用。

二.AIDL的语法:

           (1)文件类型:用AIDL书写的文件的后缀是 .aidl,而不是 .java。

       (2)数据类型:AIDL默认支持一些数据类型,在使用这些数据类型的时候是不需要导包的,但是除了这些类型之外的数据类型,在使用之前必须导包,就算目标文件与当前正在编写的 .aidl 文件在同一个包下——在 Java 中,这种情况是不需要导包的。比如,现在我们编写了两个文件,一个叫做Book.java ,另一个叫做 BookManager.aidl,它们都在 com.lypeer.aidldemo 包下 ,现在我们需要在 .aidl 文件里使用 Book 对象,那么我们就必须在 .aidl 文件里面写上 import com.lypeer.aidldemo.Book; 哪怕 .java 文件和 .aidl 文件就在一个包下。

                 · 基本数据类型(int,long,char,boolean,double,boolean,short,byte)

                  · String类型和CharSequence类型;

                  ·  List类型:只支持ArrayList,里面的每个元素必须能够被AIDL支持,List支持泛型;

                  ·  Map类型: 只支持HashMap,里面的每个元素必须能够被AIDL支持,包括key和value,Map不支持泛型 。

                  ·  Parcelable :所有事项了Parcelable接口的对象;

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

       两种AIDL文件:所有的AIDL文件大致可以分为两类。一类是用来定义parcelable对象,以供其他AIDL文件使用AIDL中非默认支持的数据类型的。一类是用来定义方法接口,以供系统使用来完成跨进程通信的。可以看到,两类文件都是在“定义”些什么,而不涉及具体的实现,这就是为什么它叫做“Android接口定义语言”。

    举个例子:

 

    例子1:

    

// Book.aidl
//第一类AIDL文件的例子
//这个文件的作用是引入了一个序列化对象 Book 供其他的AIDL文件使用
//注意:Book.aidl与Book.java的包名应当是一样的
package com.ryg.chapter_2.aidl;

//注意parcelable是小写
parcelable Book; 

 

 

  

 

    例子2:

//IBookManager.aidl
//第二类AIDL文件的例子
package com.ryg.chapter_2.aidl; //导入所需要使用的非默认支持数据类型的包 import com.ryg.chapter_2.aidl.book; interface IBookManager{ //所有的返回值前都不需要加任何东西,不管是什么数据类型 List<Book> getBookList();   //传参时除了Java基本类型以及String,CharSequence之外的类型  //都需要在前面加上定向tag,具体加什么量需而定 void addBook(in Book book); }

对象类要实现Parcelable接口:

    参考这个bolg: http://blog.csdn.net/luoyanglizi/article/details/51980630

    将要传输的数据转化为能够在内存之间流通的形式。这个转化的过程就叫做序列化与反序列化。 

     比如现在我们要将一个对象的数据从客户端传到服务端去,我们就可以在客户端对这个对象进行序列化的操作,将其中包含的数据转化为序列化流,然后将这个序列化流传输到服务端的内存中去,再在服务端对这个数据流进行反序列化的操作,从而还原其中包含的数据——通过这种方式,我们就达到了在一个进程中访问另一个进程的数据的目的。

    

AIDL中的in,out,inout: 

   http://blog.csdn.net/luoyanglizi/article/details/51958091

   AIDL中的定向 tag 表示了在跨进程通信中数据的流向,其中 in 表示数据只能由客户端流向服务端, out 表示数据只能由服务端流向客户端,而 inout 则表示数据可在服务端与客户端之间双向流通。其中,数据流向是针对在客户端中的那个传入方法的对象而言的。in 为定向 tag 的话表现为服务端将会接收到一个那个对象的完整数据,但是客户端的那个对象不会因为服务端对传参的修改而发生变动;out 的话表现为服务端将会接收到那个对象的参数为空的对象,但是在服务端对接收到的空对象有任何修改之后客户端将会同步变动;inout 为定向 tag 的情况下,服务端将会接收到客户端传来对象的完整信息,并且客户端将会同步服务端对该对象的任何变动。

          因为默认生成的模板类的对象只支持为 in 的定向 tag 。为什么呢?因为默认生成的类里面只有 writeToParcel() 方法,而如果要支持为 out 或者 inout 的定向 tag 的话,还需要实现 readFromParcel() 方法——而这个方法其实并没有在 Parcelable 接口里面,所以需要我们从头写。

      readFromParcel()方法:

        

   添加了 readFromParcel() 方法之后,我们的 Book类的对象在AIDL文件里就可以用 out 或者 inout 来作为它的定向 tag 了。

 

 

 

三.在androidstudio快速生成aidl文件

    

 

  在eclipse

 

四.后记

   过程遇到的报错:

   (1)java.lang.SecurityException: Binder invocation to an incorrect interface报错问题    

   解决方法:   客户端的aidl文件包名要与服务端的包名一样

   

 

(2)报错:系统找不到 Book.java (对象)文件

   解决方法一:

  • 修改 build.gradle 文件:在 android{} 中间加上下面的内容:
  •  
    sourceSets {
        main {
            java.srcDirs = ['src/main/java', 'src/main/aidl']
        }
    }

 

  解决方法2:

      把 java 文件放到 java 包下去:把 Book.java 放到 java 包里任意一个包下,保持其包名不变,与 Book.aidl 一致。只要它的包名不变,Book.aidl 就能找到 Book.java ,而只要 Book.java 在 java 包下,那么系统也是能找到它的。

例子:

       

 把客户端和服务端都运行到同一个虚拟机上

  最后成功的logcat

  客户端

  

  服务端

  

  AIDL的例子demo下载传送门:https://github.com/Qinxiaoshou/AIDLDemo

 

                          

posted @ 2017-05-27 22:23  QinXiao.Shou  阅读(272)  评论(0编辑  收藏  举报