天天看点

Android AIDL进程间通信(IPC)

IPC是Inter-Process Communication的缩写,意思是进程间通信。Android中IPC的方式有很多种,今天先说最灵活也是最常用的一种,即AIDL(Android Interface Definition

Language)方式。

创建多进程的方式有两种,一,给四大组件指定android:process属性,二,通过JNI在native层fork一个新的进程。今天Demo以第一种为例,因为第二种我不会。为了方便查看此Demo没有写两个工程,而是在同一个应用内给SecondActivity 指定

这样就相当于SecondActivity是另一个应用的Activity。下面开始讲解Demo。

<a target="_blank" href="http://download.csdn.net/detail/qq_17250009/9252577">Demo下载</a>

工程大纲:

Android AIDL进程间通信(IPC)

首先新建一个实现了Parcelable的Book类,用作测试Bean。

接着新建需要的aidl文件

注意:Book必须实现Parcelable接口(序列化,反序列化),参数in代表输入型参数,out代表输出型参数,inout代表输入输出型参数,否则aidl不支持。就算Book和aidl文件在同一包下,也需要导包。如果AIDL用到了自定义的parcelable对象,则必须建立一个和它同名的aidl文件,并在其中声明它为parcelable类型。AIDL接口中只支持方法,不支持静态常量,这一点区别于传统的接口。

新建上述文件夹后可以在gen/package name目录下可以查找到系统自动为我们生成的IBookManager。乍一看这个类有点乱,format后可以发现这个类并没有想象的那么复杂。在此简单分析下这个类,不感兴趣的可以略过这一阶段,直接进入下一分割线。

--------------------------------------------------------------华丽丽的分割线--------------------------------------------

首先这个IBookManager继承了IInterface接口,里面有一个抽象类Stub和两个抽象方法。

Stub里面有几个比较重要的方法:asInterface,asBinder,onTransact和一个代理类

asInterface:将服务端的Binder对象转换成客户端所需的AIDL接口类型的对象,这种对象区分进程,若在统一进程,返回服务端的Stub本身,否则返回封装后的Stub.proxy对象。

asBinder:返回当前的Binder对象

onTransact:服务端通过参数code确定客户端请求的目标方法,接着从data中取出目标方法所需的参数,然后执行目标方法,最后向reply中写入返回值。

-------------------------------------------------------------------华丽丽的分割线-------------------------------------------------------------------------

接下来就可以写我们的服务端了,这里使用一个service充当服务端。先上代码

在onBind中返回继承Stub的内部类MyServiceImpl。上文也提到过Stub继承Binder类实现了IBookManager接口并且本身是一个抽象类。所以非抽象子类需要重写getBookList()和addBook(Book book)方法。

服务器端暂时到此结束,接下来就到客户端了。

流程:A.bindService()---&gt;S.onCreate---&gt;S.onBind----&gt;&gt;A.onServiceConnected绑定成功,并获得Service对象

结束绑定按钮的监听事件--&gt;&gt;unbindService(conn)关闭连接对象--&gt;&gt;S.destory()销毁该service。

PS:SecondActivity和Maintivity代码完全一样,只是在AndroidMainfest多了一个属性,可自行创建。

点击“绑定服务”后效果如图:

Android AIDL进程间通信(IPC)

可以看到已经获取到Book的信息了。

get。

客户端到调用服务器端的方法到此结束。如果有这么一个需求:服务端有数据变动需要立即通知客户端,那么应该怎么做呢?没错,接口。需要说明的是这里的接口不是普通的接口。因为AIDL中无法使用普通接口,所以我们需要写一个aidl接口。

在IBookManaget里增加两个抽象方法

由于IBookManager增加两个抽象方法,所以相应的MyServiceImpl需要重写这两个方法。

对象是不能跨进程直接传输的,对象跨进程传输本质都是反序列化的过程。使用普通的ArrayList后Binder会把客户端传输过来的对象重新转化并生成一个对象,虽然我们注册和反注册使用的同一个客户端对象,但是这样通过Binder传递到服务器端后会产生两个全新的对象。使用RemoteCallbackList可以解决这个问题,具体优点如下:

在addBook中调用这个监听方法

接下来在MainActivity或SecondActivity中实现这个接口,并重写两个方法registerListener和unregisterListener。

在MainActivity或SecondActivity的onServiceConnected中注册监听

在MainActivity或SecondActivity的onDestroy中反注册监听

到这里基本算大功告成了,最后的最后还有一个小缺陷需要我们修复。默认情况下我们的服务器端谁都可以连接,这可不一定是我们想要的。没错,加入限权。

首先在AndroidMainfest中声明所需的限权

最后在onBinder中验证限权,没有限权返回空,无法绑定

缕清思路加写作一共花了3个多小时,终于完成了!这一大套流程下来可真不容易,希望对你有所帮助。

继续阅读