Windows上的IPC:
剪贴板:所有的进程都可以设置和修改剪贴板,也都可以从剪贴板获取内容
管道:实质是一种共享的内存,由一个进程创建,其他进程连接,并可进行双向的通信。
邮槽:一个进程创建并拥有一个邮槽,其他进程都可以打开这个邮槽并向其发送消息。
Linux上的IPC:
管道:用来连接不同进程之间的数据流。
共享内存:允许两个或多个进程共享一定的存储区,因为不需要拷贝数据,所以这是最快的一种IPC。
信号量:信号是一种异步通信机制, 信号异步通知接收信号的进程发生了某个事件。
Android上IPC:
除了继承自Linux的IPC之外还有Android特有的Binder。
这里还有Socket和ContentProvider也可以算作是进程间通信。
通过android:process = “:进程名” 属性开启。
在安卓中每个进程都分配一个独立的虚拟机,虚拟机有不同的地址空间和对象副本。
因此不同的进程就拥有独立的:1、虚拟机2、Application 3、内存空间。
则多进程造成的问题如下:
1. 静态成员和单例模式完全失效(内存不共享)
2. 线程同步机制完全失效(内存不共享)
3. SharedPreference的可靠性下降(谷歌已经废弃,不推荐)
4. Application多次创建(因为不同进程在不同的虚拟机,启动新的虚拟机又会将当前应用跑一遍)
Android中的跨进程通信:1、Intent来传递2、共享文件 3、SharePreference4、基于Binder的Messager 5、AIDL 5、Socket
这是java提供的一个序列化接口。
Serializable序列化对象会有一个serialVersionUID。在反序列化时,需要serialVersionUID和当前类相同才能够被正常反序列化。当类结构发生改变时serialVersionUID会变更。这会导致用原来类结构序列化的对象反序列化会不成功。所以一般选择手动赋值。
这是Android提供的一个序列化接口。
相对于Serializable,Parcelable在Android上的序列化效率更高。
Binder采用的是C/S结构,通过ServiceManager连接各种Manager(ActivityManager、WindowManager等)。
在AIDL过程中系统会生成对应的.aidl对象,里面的Binder也是自动生成的,同时对应的方法也会在onTransact方法中生成跨进程的方法。
当客户端和服务端在同一个进程时,方法不会走跨进程的transact过程,当跨进程时,方法需要走tracsact过程,并通过Stub(即binder)的内部代理类Proxy来完成。
在这里AIDL仅仅是我们生成Binder的工具。
在bundle中放入序列化对象,之后通过Intent进行传输。
通过文件存储和共享是比较普遍和简单的方法
同时,这里的SharedPreference也是个典型例子。
它是一个轻量级的IPC方案,底层实现是AIDL。不过整个通信过程是以串行的方式进行,不适合大批量的并发请求。
在Messenger通信过程中,处理message是在Handler中进行的。A要发送信息给B需要持有B的Messager对象才行。
服务端:
客户端:
messager要实现通信,需要对方持有自己的messager对象。在Service中Messager对象是通过onBinder返回给客户端的。
服务器改动:
客户端的改动:
因为客户端要处理Message所以需要创建Handler和自己的Messager,通过Message的replyTo将自己的Messager对象发送给服务端。
服务端:
在aidl文件夹中建立aidl的接口:
注意:aidl服务所在包名最好和客户端的包名结构一致。
Eg:
这是我的一个应用的aidl
客户端的实现:
通过binderService的方式去绑定服务并获取binder,从而实现和服务器的通信。这里,除了用到了aidl文件基本上整体和进程内与service通信没什么区别。
服务器端修改:
在aidl文件中建立一个.aidl的接口文件:
然后给原来的IBookManager添加注册监听和取消监听的方法
相应的在主工程下实现,将监听放到一个管理监听的ArrayList中
在收到新书之后去通知对应的监听列表
客户端修改:
在获取服务端的binder之后向其注册监听
在onDestroy时解注册监听:
但这里会报错:
对象跨进程的本质;Binder会把客户传递过来的序列化对象转化并生成一个新的对象。
为了防止这个异常,Android提供了RemoteCallbackList专门用来保存在服务端的监听。但这个RemoteCallbackList使用方法很特殊:
1、 无论是在服务端还是客户端最好都运行在非UI线程中
2、 对于服务端意外死亡的情况,我们最好为服务设置死亡监听DeathRecipient,从而重连远程服务。
3、 AIDL权限验证:
客户端验证:
a) 在要使用该该服务的Mainifest中添加permission权限
b) 在obBind方法中添加验证方法
服务端验证:
在服务端的onTransact中进行验证,用户的Uid和Pid。注意:要使用我们的自定义权限的包名必须以com.ryg开始。
其底层也是采用Binder。看似是SQLite数据库,实际上对于数据存储的方式没有要求。
主要针对的数据格式为:1、表格的形式2、文件数据(图片、视频等)
监听:在update、insert和delete方法引起数据源改变的时候,可以通过ContentResolver的notifyChange来通知外界。
并发:query、update、insert、delete存在多线程并发,需要做好线程同步。
不能在主线程中访问网络。
对于多个地方使用到aidl的情况(每个aidl通信都要通过service),为了节省资源,我们将所有aidl放到同一个Service中去处理。
用法:
在aidl文件中申明一个IBinderPool接口
在service中实现为:
整体实现:
调用方法: