您的位置:首页 > 移动开发 > Android开发

解读Android之Service(3)AIDL

2016-02-26 10:17 435 查看
本文翻译自android官方文档

Android Interface Definition Language(AIDL)能够让我们定义自己的编程接口,该接口可以使得客户端和service之间进行跨进程通信(interprocess communication,IPC)。通常,在android中无法直接跨进程通信。因此,需要把传递的对象分解成系统可以识别的原始状态(数据),并将它们跨进程序列化marshalling。由于marshalling过程繁琐,因此android通过AIDL处理。

注意:只有当我们允许不同应用程序的客户端获取service来进行IPC,并且在service中需要处理多线程时,AIDL才是必须的。绝大多数应用程序都不应该用AIDL来创建Bound Service,因为这可能需要多线程处理能力并且会让代码变得更为复杂。因此,AIDL对绝大多数应用程序都不适用。如果只是在应用程序内部使用,并且不需要跨进程,我们可以通过继承Binder类直接进行交互,这种是最常见的方式。若跨进程IPC且不需要处理多线程问题可以通过使用Messenger方法,因为Messenger把所有请求都放在一个线程中,因此不必担心线程安全问题。

(下面的理解上还有些问题)在开始设计AIDL接口之前,需要注意的是调用AIDL接口是直接的调用方法,我们不应该假设调用方法发生在子线程。从本地进程和远程进程中的线程调用是不同的:
在本地进程中调用。若在主线程中调用,则AIDL接口会在主线程中执行。若是另外的子线程,则该线程执行service中的代码。因此 若只有本地线程获取service,我们能够完全控制。这种情况不应该使用AIDL,而是继承Binder实现。
若是远程进程调用,则AIDL的实现必须要保证完全地线程安全。这是因为若是支持远程调用的话可能需要同时处理多个调用(并发处理)。
单向改变远程调用行为。当使用这种方式时,远程调用不会阻塞;它简单的发送数据,并立刻返回。最终,接口实现接收向常规的通过Binder线程池调用一样处理远程调用。若单向用在本地调用,则不会影响并且调用仍是异步的。

上述内容理解有的问题,须再查阅资料并验证,同时请各位不吝赐教。


定义AIDL接口

AIDL接口必须定义在
.aidl
文件中(命名满足java语法),并同时保存在service所在的应用程序和其它绑定该service的应用程序(需要通过AIDL进行IPC的service)中,保存位置为源代码中
src/
目录下。

当我们新建一个
.aidl
文件时,android SDK工具就会根据该文件自动生成一个IBinder接口,并且保存在
gen/
目录下。service必须实现IBinder接口,客户端才能绑定service并调用方法获得该对象进行IPC。

上面的目录是在eclipse中的,在android studio中则在: 



为了能够创建使用AIDL的service,必须要实现以下步骤:
创建
.aidl
文件 

该文件定义了带有方法声明的编程接口
实现接口 

android SDK工具使用java生成一个接口,依据是根据
.aidl
文件。这个接口中有一个内部抽象类Stub,该类继承了Binder类,并且实现了AIDL接口中的方法,我们必须继承Stub类和实现其方法。
将接口暴露给客户端 

实现Service类,覆盖
onBind()
方法,并且返回Stub的实现。

注意:在我们第一次发布之后的改变AIDL接口都要保证对原来的版本的兼容性,避免其它应用无法访问我们的service(其它客户端可能拷贝的还是原来的接口版本)。

下面详细介绍以上几步:


1. 创建
.aidl
文件

AIDL需要满足一些简单的语法:能够使我们声明一个接口,该接口可以包含一个或多个方法,且能够带有参数和返回值。参数和返回值可以是任何类型的甚至是其它AIDL生成的接口。

每个
.aidl
文件必须定义一个接口,并且只需要接口声明和方法声明。

默认情况下,AIDL支持以下数据类型:
java中八大基本数据类型
String
CharSequence
List 

当然,List中的类型也需要是AIDL支持的类型。通常使用List声明变量,而具体的类型(例如ArrayList)在定义时确定。
Map 

和List用法一样。

若是使用上述以外的类型(例如自定义类)必须导入相关声明,即使在同一个包中定义的。

在定义AIDL接口时,需要注意以下几点:
方法可以带有0个或多个参数,可以选择有无返回值。
所有的非基本数据类型都需要指定一个方向来标记数据的流向(进,出,进出同时)。基本数据类型默认是进,且不能改变。我们有必要限制数据方向(真正需要的方向),原因在于marshalling参数的代价消耗大。
文件中的所有代码注释都被包含在生成的IBinder接口中,除非是import和package之前注释的。
只支持方法,不支持静态成员变量。且方法不能有修饰符。
需要手动输入包名(android studio不需要手动)

下面有一个例子:
<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">package</span> com.sywyg.servicetest;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> com.sywyg.servicetest.Man;
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Declare any non-default types here with import statements</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 需要导入自定义类型的位置</span>
interface IRemoteService{
<span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** Request the process ID of this service, to do evil things with it. */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> getPid();

<span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> basicTypes(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> anInt, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> aLong, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> aBoolean, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span> aFloat,
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">double</span> aDouble, String aString);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Man getMan();</span>
}

</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li></ul>


然后系统就会自动生成一个IRemoteService.java(对应IRemoteService.aidl)文件。 

有的编译器是立刻生成,有的则在编译应用程序时生成,这点注意。


2. 实现接口

自动生成文件包含一个内部抽象类Stub,继承了Binder并是父类接口的一个抽象实现,实现了
.aidl
文件中的所有方法。Stub同时定义了一些其他有用的方法,尤其是
asInterface()
方法,该方法接收一个IBinder对象,返回Stub接口的实现。Stub英文表示存根的意思,该类在服务端进程,我们必须继承该类并实现aidl接口中的方法。

下面用一个匿名类实现简单的接口实例:
<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">    <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
* 定义一个匿名内部类实现aidl接口,需要继承IRemoteService.Stub类
* 在.aidl文件中声明的方法需要在这里实现具体功能
*/</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> IRemoteService.Stub mBinder = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> IRemoteService.Stub() {
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> <span class="hljs-title" style="box-sizing: border-box;">getPid</span>(){
Log.d(TAG,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"getPid is executed ..."</span>);
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> android.os.Process.myPid();
}
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">basicTypes</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> anInt, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> aLong, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> aBoolean,
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span> aFloat, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">double</span> aDouble, String aString) {
Log.d(TAG,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"basicTypes is executed ..."</span>);
}
};
</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul>


Stub实现了Binder类(定义了远程过程调用协议Remote Procedure Call Protocol RPC),因此mBinder可以传输给客户端。

在实现AIDL时需要注意一下几点:
调用不能保证在主线程中执行,我们应该考虑多线程问题,并保证service是线程安全的。
默认情况,RPC调用是异步的。若service需要长时间的操作要保证调用不能发生在主线程中,因为这个可能出现应用程序无法响应问题Application Not Responding ANR。因此我们应该保证调用发生在另外的子线程中。
不会给调用者抛出异常。


3. 将接口暴露给客户端

为service实现了AIDL接口,我们应该把接口暴露给客户端,使得他们能够绑定它。下面给出完整的代码,说明如何实现:
<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">
<span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
* 通过AIDL实现IPC
*<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @author</span> sywyg
*<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @since</span> 2015.7.16
*/</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">AIDLService</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Service</span> {</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> String TAG = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"result"</span>;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">AIDLService</span>() {
}

<span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
* 定义一个匿名内部类实现aidl接口,需要继承IRemoteService.Stub类
* 在.aidl文件中声明的方法需要在这里实现具体功能
*/</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> IRemoteService.Stub mBinder = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> IRemoteService.Stub() {
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> <span class="hljs-title" style="box-sizing: border-box;">getPid</span>(){
Log.d(TAG,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"getPid is executed ..."</span>);
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> android.os.Process.myPid();
}
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">basicTypes</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> anInt, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> aLong, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> aBoolean,
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span> aFloat, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">double</span> aDouble, String aString) {
Log.d(TAG,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"basicTypes is executed ..."</span>);
}
};

<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> IBinder <span class="hljs-title" style="box-sizing: border-box;">onBind</span>(Intent intent) {

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> mBinder;
}
}
</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li></ul>


那么,当客户端调用
bindService()
连接service时,客户端回调
onServiceConnected()
方法接收mBinder实例(service的
onBinder()
方法返回的)。

客户端必须也能够获得该接口类,因此当客户端和service在不同的应用程序时,客户端应用程序必须复制一份
.aidl
文件,这样才能获得AIDL中的方法。

当客户在
onServiceConnected()
方法中接收IBinder对象时,必须通过调用
YourServiceInterface.Stub.asInterface(service)
转换为YourServiceInterface类型。如下:
<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">
IRemoteService mIRemoteService;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> ServiceConnection mConnection = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ServiceConnection() {
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onServiceConnected</span>(ComponentName name, IBinder service) {
Log.d(TAG,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"绑定成功"</span>);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Following the example above for an AIDL interface,</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// this gets an instance of the IRemoteService, which we can use to call on the service</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 还是接着上面的例子,通过这种方式获得IRemoteService的一个实例,</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 这样,我们可以在客户端进行处理了。</span>
mIRemoteService = IRemoteService.Stub.asInterface(service);

mBound = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>;
}

<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onServiceDisconnected</span>(ComponentName name) {
mBound = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>;
}
};
</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li></ul>


通过IPC传递对象

我们可以实现通过IPC把对象从一个进程传递到另一个进程中。但是,我们必须要确保在另一个进程中可以获得该对象(即需要该类的代码),并且该类需要支持Parcelable接口。必须要支持Parcelable,这样系统才能将对象分解为基本数据类型(能够跨进程marshalled)。

注意:Parcelable是一个接口,实现该接口的类实例能够保存在Parcel中并从中恢复。该类中必须有一个名叫CREATOR的静态成员变量,该成员是Parcelable.Creator的一个实现实例。

为了创建支持Parcelable协议的类,必须完成以下几点:
该类必须实现Parcelable接口;
实现
writeToParcel()
方法,记录当前对象的状态(成员变量等),并用Parcel保存。还要实现
describeContents()
,一般返回0;
添加静态成员变量CREAROR,该成员是Parcelable.Creator的一个实现实例;
最后创建一个
.aidl
文件声明该parcelable类(例如下面的Rect.aidl文件)。若你正在进行自定义生成过程,不要添加
.aidl
文件,这是因为,它类似C语言的头文件,不会进行编译的。???茫然

AIDL通过上述办法产生marshall和unmarshall对象。

下面是一个实现Parcelable接口的类Rect,首先要有Rect.aidl文件:
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">package</span> android.graphics;

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Declare Rect so AIDL can find it and knows that it implements</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// the parcelable protocol.</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 声明Rect,AIDL好找到并确认它实现了parcelable协议</span>
parcelable Rect;
</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>


下面是Rect类:
<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> android.os.Parcel;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> android.os.Parcelable;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Rect</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Parcelable</span> {</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> left;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> top;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> right;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> bottom;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> Parcelable.Creator<Rect> CREATOR = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span>
Parcelable.Creator<Rect>() {
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Rect <span class="hljs-title" style="box-sizing: border-box;">createFromParcel</span>(Parcel in) {
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Rect(in);
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Rect[] <span class="hljs-title" style="box-sizing: border-box;">newArray</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> size) {
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Rect[size];
}
};

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">Rect</span>() {
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-title" style="box-sizing: border-box;">Rect</span>(Parcel in) {
readFromParcel(in);
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">writeToParcel</span>(Parcel out) {
out.writeInt(left);
out.writeInt(top);
out.writeInt(right);
out.writeInt(bottom);
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">readFromParcel</span>(Parcel in) {
left = in.readInt();
top = in.readInt();
right = in.readInt();
bottom = in.readInt();
}
}
</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li></ul>


Parcel同样可以写其它类型的数据。

警告:不要忘记从另一个进程中获取数据时的安全问题。上面的例子,Rect获取四个数,但是这取决于你获得多少数据(读写顺序要一致)。

更多关于Parcelable,可以参考:Activity之间通信

下面总结一下IPC调用过程


调用IPC

客户端必须完成以下步骤才能实现调用远程接口:
在项目中包含
.aidl
文件。
声明一个IBinder对象实例(基于AIDL产生的)。
实现ServiceConnection。
调用
Context.bindService()
,并传递ServiceConnection的实现。
onServiceConnected()
实现中,我们可以接受IBinder的一个实例(名为service)。调用
asInterface()
转换成接口实例。
调用在接口中定义的方法。必须要捕获DeadObjectionException异常(当连接断开时),这是调用远程方法的唯一异常。
调用
Context.unBindService()
解除连接。

调用IPC service注意事项:
对象是跨进程计数的引用类型,上一章讲的一样,可能会造成内存泄漏。
能够发送匿名对象作为方法参数。
转自http://blog.csdn.net/wangyongge85/article/details/46907599
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: