Android面试Android跨进程通信IPC
Posted Rose J
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android面试Android跨进程通信IPC相关的知识,希望对你有一定的参考价值。
目录
他是谁?
IPC是Inter-Process Communication的缩写,含义为进程间通信或者跨进程通信
windows IPC机制
剪贴板,管道,邮槽
Linux IPC机制
命名管道,共享内容,信号量
哪里需要用到多进程?
系统为每个进程分配的内存是有限的,比如在以前的低端手机上常见是 16M,现在的机器内存更大一些,32M、48M,甚至更高。但是,总是有限的,毕竟一个手机出厂之后 RAM 的大小就定了,总是无法满足所有应用的需求。
一个明智的选择就是使用多进程,将一些看不见的服务、比较独立而又相当占用内存的功能运行在另外一个进程当中,主动分担主进程的内存消耗。常见如,应用中的推送服务,音乐类 App 的后台播放器等等,单独运行在一个进程中。
还有互相拉起,一个应用去调用其他应用的数据
service的保活,可以给服务创建一个独立的进程。
可以把一些存在oom的操作,比如下载一张很大的图片,放到一个新的进程,这样就算出现了内存溢出,也不会影响主线程
调用闹钟,拨打电话,推送
1.序列化
serializable和parcelable接口可以完成对象的序列化过程,当我们需要通过Intent和Binder传输数据时就需要使用parcelable或者serializable,还有的时候我们需要把对象持久化到存储设备(硬盘)或者通过网络传输给其他客户端,这个时候也需要使用serializable来完成对象的持久化。
1.serializable和parcelable区别
1.serializable是java中的序列化接口,其使用起来简单但是开销很大,序列化和反序列化过程需要大量的I/O操作。
2.parcelable是android中的序列化方式,因此更适合在Android平台上,它的缺点就是使用起来稍微麻烦一点,但是它的效率很高,这是Android推荐的序列化方式,因此我们首选parcelable
3.parcelable主要用在内存序列化上,通过parcelable将对象序列化到存储设备中 或者 将对象序列化后 通过网络传输也都是可以的,但是这个过程稍显复杂,因此在这两者情况下选serializable。
2.Binder
1.定义
Binder是Android中的一个类,他实现了IBinder接口,
1.从IPC角度来说
Binder是Android中的一种跨进程通信方式,Binder还可以理解为一种虚拟的物理设备,它的设备驱动是dev/binder,该通信方式Linux中没有
2.从Android Framework角度来说
Binder是ServiceManager连接各Manager(ActivityManager,WindowManager,等等)和相应的ManagerService的桥梁;
3.从Android应用层来说
Binder是客户端和服务端进行通信的媒介,当bindService的时候,服务端会返回一个包含服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务
2.架构
Linux内存被分为用户空间和内核空间,用户空间需要经过系统调用才能访问到内核空间。
Binder整体基于C/S架构。运行在内核空间的Binder驱动程序,会为用户空间暴露出一个设备文件/dev/binder
,进程间通过该文件来建立通信通道。
3.优点
- 好用:易用的C/S架构(借助AIDL后只需编写业务逻辑)
- 性能:用mmap进行内存映射,只需一次拷贝
- 安全:内核态管理身份标记,每个App有UID来校验权限,同时支持实名(系统服务)和匿名(自己创建的服务)
3.Android 中的IPC方式
1.Bundle
2.文件共享
3.Messenger
4.AIDL
5.ContentProvider
6.Socket
Buudle
Bundle实现了Parcelable接口,所以它可以很方便的在不同进程间传输 。 Bundle在Activity之间传递数据,传递的数据可以是boolean、byte、int、long、float、double、string等基本类型或它们对应的数组,也可以是对象或对象数组。当Bundle传递的是对象或对象数组时,必须实现Serializable 或Parcelable接口。
所以Bundle其实是一种数据“容器”。通过Intent来传递。
这里除了数据传递,在Android的艺术探索中有提到另外一种场景
:比如A进程正在进行一个计算,计算完成后它要启动B进程的一个组件并把计算结果传输给B进程,但是这个计算结果不支持放进Bundle中,因此无法用Intent来传输,但是用其他IPC方式会略显复杂。
所以我们通过Intent启动进程B的一个service组件(比如IntentService)让service在后台计算,计算完毕以后再启动B进程中真正想要启动目标组件,由于Service也运行在B进程中,所以目标组件就可以直接获取计算结果。这样也就是实现了跨进程的效果。
文件共享
共享文件也是一种进程间通信方式,两个进程通过读/写同一个文件来交换数据,比如A进程把数据写入文件,B进程通过读取这个文件来获取数据。存在并发问题
Messenger
Messenger翻译为信使,通过它可以在不同进程中传递Message对象,Message中放入我们需要传递的数据,就可以轻松的实现数据的进程间传递了。Messenger是一种轻量级IPC方案,他的底层实现原理AIDL。
它对AIDL做了封装,使得我们可以更简便的进行进程间通信,同时,由于他一次处理一个请求,因此在服务端中我们不用考虑线程同步的问题,这是因为服务端中不存在并发执行的情形。
实现一个Messenger:分为服务端和客户端
1.服务端进程
首先,我们需要在服务端创建一个Service来处理客户端的连接请求,同时创建一个handler并通过它来创建一个Messenger对象,然后在Service的onBind中返回这个Messenger对象底层的Binder即可
2.客户端进程
客户端进程中,首先要绑定服务端的service,绑定成功后服务端返回的IBinder对象创建一个Messenger,通过这个Messenger就可以向服务端发送消息了,发消息类型为Message对象,如果需要服务端能够回应客户端,就和服务端一样,我们还需要创建一个Handler并创建一个新的Messenger,并把这个Messenger对象通过Message的replyTo参数传递给服务端,服务端通过这个replyTo参数就可以回应客户端。
Messenger是以串行的方式处理客户端发来的消息,如果大量的消息同时发送到服务端,服务端仍然只能一个一个处理,所以Messenger不太合适了。而且Messenger的作用主要是为了传递消息,但很多时候我们需要跨进程调用服务端的方法,这种情形用Messenger就无法做到了,但是我们可以用AIDL来实现跨进程的方法调用。
AIDL
AIDL是Messenger底层的实现,因此Messenger本质上也是AIDL,只不过系统为我们做了封装从而方便上层的调用而已。
AIDL的使用
1.服务端
服务端首先要创建一个service来监听客户端的连接请求,然后创建一个AIDL文件,将暴露给客户端的接口在这个AIDL文件中声明,最后在Service中实现这个AIDL接口
2.客户端
首先需要绑定服务端的Service,绑定成功以后,将服务端返回的Binder对象转成AIDL接口所属的类型,接着就可以调用AIDL中的方法了。(实际的实现没有这么简单,这只是大致描述)
ContentProvider
系统预置了许多ContentProvider,比如通讯录信息,日程表信息,要跨进程访问这些信息,只需要通过ContentProvider的query,updata,insert,delete方法即可。也可以实现自定义ContentProvider,然后在其他应用中获得ContentProvider中的数据从而实现进程间通信。
Socket
socket也称套接字,是网络通信中的概念,它分为流失套接字和用户数据报套接字两种,分别对应于网络的传输控制层中的tcp和udp协议。
Binder连接池
在这种模式下,整个工作机制是这样的,每个业务模块创建自己的AIDL接口并实现此接口,这个时候不同业务模块之间是不能有耦合的,所有实现细节我们要单独开来,然后想服务端提供自己的唯一标识和其对应的Binder对象,对于服务端来说,只需要一个service就可以了,服务端提供一个queryBinder接口,这个接口能够根据业务模块的特征来返回相应的Binder对象给他们,不停的业务模块拿到所需的Binder对象后就可以进行远程方法调用了。
由此可见,Binder连接池的主要作用就是将每个业务模块的Binder请求统一转发到远程Service中去执行,从而避免了重复创建Service的过程
以上是关于Android面试Android跨进程通信IPC的主要内容,如果未能解决你的问题,请参考以下文章