AIDL笔记

1.aidl支持类型

* Java中的八种基本数据类型,包括 byte,short,int,long,float,double,boolean,char。
* String 类型。
* CharSequence类型。
* List类型:List中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的parcelable。List可以使用泛型。
* Map类型:Map中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的parcelab le。Map是不支持泛型的。

2.定义方式
定义IBookManager.aidl,在adil文件中声明相应的方法

package com.example.arvin.myapplication;

// Declare any non-default types here with import statements
import com.example.arvin.myapplication.Book;
interface IBookManager {
    List getBookList();

    void addBook(in Book book);

    Book findBook(in String bookId);

    void addBookOut(out Book book);
}

aidl支持自定义类型,但是必须序列化(实现parcelable)
自定义parceable需要声明一个同名的aidl文件 用parcelable 声明类型

// Books.aidl
package com.example.arvin.myapplication;

// Declare any non-default types here with import statements
parcelable Book;

aidl使用默认支持的类型不需要导包,使用其他类型需要导包,即使是在同一个包路径下,这点和java是有区别的

3.aidl自动生成文件源码
先截个图
AIDL笔记_第1张图片
可以看到,aidl自动生成了同名java文件 是一个接口类型,和aidl中一样
java文件的内容包括两部分

//第一部分
public void addBook(com.example.arvin.myapplication.Book book) throws android.os.RemoteException;

public com.example.arvin.myapplication.Book findBook(java.lang.String bookId) throws android.os.RemoteException;

public void addBookOut(com.example.arvin.myapplication.Book book) throws android.os.RemoteException;

这三个方法是aidl接口中声明的方法

第二部分就Stub,继承Binder,而Binder 实现了IBinder。Stub还实现了jiekaidl声明的接口(本例中是IBookManager)

展开Stub 看看具体的东西
AIDL笔记_第2张图片
看起来也比较清楚,
1.声明了4个整型常量,对应aidl中声明的方法
2.DESCRIPTOR aidl描述,通常使用类全名
3.定义了一个内部类Proxy,从名字上推测上代理类,干嘛用的后面看
4.实现了Binder里面一些方法,比如onTransact,再比如asBinder, 先不管,后面看呗

我们先看看Proxy都干了什么,上图
AIDL笔记_第3张图片

看起来也还挺清楚
1.声明了一个IBinder对象,在构造方法中赋值,中asBinder()方法中返回这个对象
2.实现了我们在Aidl接口中声明的4个方法。

一起来看看这几个方法
AIDL笔记_第4张图片
这里先对比前两个方法getBookList()和addBook(int Book book)
AIDL笔记_第5张图片
首先定义了两个Parcel 对象,通过对比我们可以看出来,_data应该是用来保存传入参数的,_reply是返回值

if ((book != null)) {   //传入参数不为空,writeInt(1) 并写入_data中
    _data.writeInt(1);
    book.writeToParcel(_data, 0);
} else {
    _data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();   //这一句 如果没满足特定条件直接抛出异常,估计应该是校验用的

_result = com.example.arvin.myapplication.Book.CREATOR.createFromParcel(_reply);  //返回对象赋值

看这里,看这里
AIDL笔记_第6张图片
当 形参声明为 out的时候,_data是没有被赋值的,先标个记,一会来看

还有这个
AIDL笔记_第7张图片
当声明为inout的时候,多了一段

if ((0 != _reply.readInt())) {
    book.readFromParcel(_reply);
}
//这一句应该是改变了传入参数,就是说client的数据会受到影响,发生变化咯

可以看到这里面的操作基本都是赋值,那实际工作的代码应该就是

mRemote.transact(Stub.TRANSACTION_addBookInOut, _data, _reply, 0);

跟踪代码发现,这里最终会去走

public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)

上面的声明很清楚了,code就是最上面提到的生成的对应4个方法的int值,data就是传参,reply就是保存返回值的

来看一下具体的代码 不截图来上源码好了


@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
    switch (code) {
        case INTERFACE_TRANSACTION: {
            reply.writeString(DESCRIPTOR);
            return true;
        }
        case TRANSACTION_getBookList: {
            data.enforceInterface(DESCRIPTOR);
            java.util.List<com.example.arvin.myapplication.Book> _result = this.getBookList();
            reply.writeNoException();
            reply.writeTypedList(_result);
            return true;
        }
        case TRANSACTION_addBook: {
            data.enforceInterface(DESCRIPTOR);
            com.example.arvin.myapplication.Book _arg0;
            if ((0 != data.readInt())) {
                _arg0 = com.example.arvin.myapplication.Book.CREATOR.createFromParcel(data);
            } else {
                _arg0 = null;
            }
            this.addBook(_arg0);
            reply.writeNoException();
            return true;
        }
        case TRANSACTION_findBook: {
            data.enforceInterface(DESCRIPTOR);
            java.lang.String _arg0;
            _arg0 = data.readString();
            com.example.arvin.myapplication.Book _result = this.findBook(_arg0);
            reply.writeNoException();
            if ((_result != null)) {
                reply.writeInt(1);
                _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
            } else {
                reply.writeInt(0);
            }
            return true;
        }
        case TRANSACTION_addBookOut: {
            data.enforceInterface(DESCRIPTOR);
            com.example.arvin.myapplication.Book _arg0;
            _arg0 = new com.example.arvin.myapplication.Book();
            this.addBookOut(_arg0);
            reply.writeNoException();
            if ((_arg0 != null)) {
                reply.writeInt(1);
                _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
            } else {
                reply.writeInt(0);
            }
            return true;
        }
        case TRANSACTION_addBookInOut: {
            data.enforceInterface(DESCRIPTOR);
            com.example.arvin.myapplication.Book _arg0;
            if ((0 != data.readInt())) {
                _arg0 = com.example.arvin.myapplication.Book.CREATOR.createFromParcel(data);
            } else {
                _arg0 = null;
            }
            this.addBookInOut(_arg0);
            reply.writeNoException();
            if ((_arg0 != null)) {
                reply.writeInt(1);
                _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
            } else {
                reply.writeInt(0);
            }
            return true;
        }
    }
    return super.onTransact(code, data, reply, flags);
}

通过代码很容易看出来,Proxy是运行在服务端的,为什么这么说呢
AIDL笔记_第8张图片
这里面有这一句
java.util.List


class Bookmanager extends IBookManager.Stub {
              ...
}

至此,aidl的调用流程也就很清楚了,然后有请灵魂画师给画个图
AIDL笔记_第9张图片
什么鬼这是???
还是请出任玉刚老师的图吧(这个不算侵权吧)
AIDL笔记_第10张图片
看起来还是蛮像的啊

  1. in out inout表示的意义
    通过源码可以知道,in的话,service改变了传入参数,不会引起client变化
    out 不会将形参的对象传入到service,而是会在service中新建一个对象,但是在服务端改变这个对象,会引起client传入对象发生变化
    inout 双向的,就是上面两句话综合下
    所以呢,这个表示的是形参的数据流向,官方上好像说的是大多数情况下是in,对了,默认支持的类型是不要这个
    还有啊,out 和inout 要在Parceable中声明下面这个方法才可以使用
public void readFromParcel(Parcel reply) {
    bookId = reply.readString();
    bookName = reply.readString();
}

那就先到这里了,有时间的话再去深入Binder,IBinder,记得开头好像有几个asBinder的坑没填,后面填上

你可能感兴趣的:(android学习)