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

Android开发艺术探索学习笔记2——IPC机制

2017-09-24 12:05 525 查看

Android开发艺术探索学习笔记2——IPC机制

IPC简介:

Windows上的IPC:

剪贴板:所有的进程都可以设置和修改剪贴板,也都可以从剪贴板获取内容

管道:实质是一种共享的内存,由一个进程创建,其他进程连接,并可进行双向的通信。

邮槽:一个进程创建并拥有一个邮槽,其他进程都可以打开这个邮槽并向其发送消息。

Linux上的IPC:

管道:用来连接不同进程之间的数据流。

共享内存:允许两个或多个进程共享一定的存储区,因为不需要拷贝数据,所以这是最快的一种IPC。

信号量:信号是一种异步通信机制, 信号异步通知接收信号的进程发生了某个事件。

Android上IPC:

除了继承自Linux的IPC之外还有Android特有的Binder。

这里还有Socket和ContentProvider也可以算作是进程间通信。

Android中多进程

多进程的开启:

通过android:process = “:进程名” 属性开启。

在安卓中每个进程都分配一个独立的虚拟机,虚拟机有不同的地址空间和对象副本。

 

跨进程带来的问题

因此不同的进程就拥有独立的:1、虚拟机2、Application 3、内存空间。

则多进程造成的问题如下:

1.     静态成员和单例模式完全失效(内存不共享)

2.     线程同步机制完全失效(内存不共享)

3.     SharedPreference的可靠性下降(谷歌已经废弃,不推荐)

4.     Application多次创建(因为不同进程在不同的虚拟机,启动新的虚拟机又会将当前应用跑一遍)

跨进程的解决方式

Android中的跨进程通信:1、Intent来传递2、共享文件 3、SharePreference4、基于Binder的Messager 5、AIDL  5、Socket

IPC的基础概念

Serializable接口:

这是java提供的一个序列化接口。

Serializable序列化对象会有一个serialVersionUID。在反序列化时,需要serialVersionUID和当前类相同才能够被正常反序列化。当类结构发生改变时serialVersionUID会变更。这会导致用原来类结构序列化的对象反序列化会不成功。所以一般选择手动赋值。

Parcelable接口:

这是Android提供的一个序列化接口。

相对于Serializable,Parcelable在Android上的序列化效率更高。

Binder:

 Binder采用的是C/S结构,通过ServiceManager连接各种Manager(ActivityManager、WindowManager等)。

在AIDL过程中系统会生成对应的.aidl对象,里面的Binder也是自动生成的,同时对应的方法也会在onTransact方法中生成跨进程的方法。

当客户端和服务端在同一个进程时,方法不会走跨进程的transact过程,当跨进程时,方法需要走tracsact过程,并通过Stub(即binder)的内部代理类Proxy来完成。



在这里AIDL仅仅是我们生成Binder的工具。

Android中的IPC机制:

使用Bundle

在bundle中放入序列化对象,之后通过Intent进行传输。

使用文件共享

通过文件存储和共享是比较普遍和简单的方法

同时,这里的SharedPreference也是个典型例子。

使用Messenger

它是一个轻量级的IPC方案,底层实现是AIDL。不过整个通信过程是以串行的方式进行,不适合大批量的并发请求。

在Messenger通信过程中,处理message是在Handler中进行的。A要发送信息给B需要持有B的Messager对象才行。

客户端向服务器发送信息

服务端:



客户端:



messager要实现通信,需要对方持有自己的messager对象。在Service中Messager对象是通过onBinder返回给客户端的。

 

服务器向客户端发送信息:

服务器改动:





客户端的改动:





因为客户端要处理Message所以需要创建Handler和自己的Messager,通过Message的replyTo将自己的Messager对象发送给服务端。

使用AIDL

普通的使用

服务端:

在aidl文件夹中建立aidl的接口:



注意:aidl服务所在包名最好和客户端的包名结构一致。

Eg:

这是我的一个应用的aidl

 






客户端的实现:





通过binderService的方式去绑定服务并获取binder,从而实现和服务器的通信。这里,除了用到了aidl文件基本上整体和进程内与service通信没什么区别。

客户端对服务器的监听:

服务器端修改:

在aidl文件中建立一个.aidl的接口文件:



然后给原来的IBookManager添加注册监听和取消监听的方法



相应的在主工程下实现,将监听放到一个管理监听的ArrayList中



在收到新书之后去通知对应的监听列表



客户端修改:

在获取服务端的binder之后向其注册监听







在onDestroy时解注册监听:



但这里会报错:



监听异常的注意事项:

对象跨进程的本质;Binder会把客户传递过来的序列化对象转化并生成一个新的对象。

为了防止这个异常,Android提供了RemoteCallbackList专门用来保存在服务端的监听。但这个RemoteCallbackList使用方法很特殊:



AIDL的其他注意事项:

1、      无论是在服务端还是客户端最好都运行在非UI线程中

2、      对于服务端意外死亡的情况,我们最好为服务设置死亡监听DeathRecipient,从而重连远程服务。

3、      AIDL权限验证:

客户端验证:

a)     在要使用该该服务的Mainifest中添加permission权限

b)     在obBind方法中添加验证方法





服务端验证:

在服务端的onTransact中进行验证,用户的Uid和Pid。注意:要使用我们的自定义权限的包名必须以com.ryg开始。



使用ContentProvider

其底层也是采用Binder。看似是SQLite数据库,实际上对于数据存储的方式没有要求。

主要针对的数据格式为:1、表格的形式2、文件数据(图片、视频等)

监听:在update、insert和delete方法引起数据源改变的时候,可以通过ContentResolver的notifyChange来通知外界。

并发:query、update、insert、delete存在多线程并发,需要做好线程同步。

使用socket

不能在主线程中访问网络。

 

Binder连接池

对于多个地方使用到aidl的情况(每个aidl通信都要通过service),为了节省资源,我们将所有aidl放到同一个Service中去处理。

用法:

在aidl文件中申明一个IBinderPool接口





在service中实现为:



整体实现:















调用方法:



 

AIDL的选择:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android ipc