当启动App且没有运行其他组件时,Android 系统会使用单个执行线程为应用启动新的 Linux 进程。默认情况下一个App中的所有组件都在同一个进程和线程中,但也可以通过配置manifest使组件运行在单独的进程中。在实际应用场景中,Android四大组件都支持属性,以决定在哪个进程运行,因此进程间通信就会变得尤为重要。
Android 利用远程过程调用 (RPC) 提供了一种进程间通信 (IPC) 机制,通过这种机制,由 Activity 或其他应用组件调用的方法将(在其他进程中)远程执行,而所有结果将返回给调用方。 这就要求把方法调用及其数据分解至操作系统可以识别的程度,并将其从本地进程和地址空间传输至远程进程和地址空间,然后在远程进程中重新组装并执行该调用。 然后,返回值将沿相反方向传输回来。 Android 提供了执行这些 IPC 事务所需的全部代码,因此我们只需集中精力定义和实现 RPC 编程接口即可。
基本概念
- RPC:Remote Procedure Call (远程过程调用) 是一种计算机通讯协议,它为我们定义了计算机 C 中的程序如何调用另外一台计算机 S 的程序,让程序员不需要操心底层网络协议,使得开发包括网络分布式多程序在内的应用程序更加容易。
- IDL:Interface Description Language (接口定义语言)。通过一种中立的方式来描述接口,使得在不同平台上运行的对象和用不同语言编写的程序可以相互通信交流。
- IPC:Inter-Process Communication (进程间通信)。Android 基于 Linux,而 Linux 出于安全考虑,不同进程间不能之间操作对方的数据,这叫做“进程隔离”。
- AIDL:Android Interface Definition Languag(Android接口定义语言)。设计这门语言的目的是为了实现进程间通信,尤其是在涉及多进程并发情况下的进程间通信。
- 进程隔离:出于安全考虑,一个进程不能操作另一个进程的数据,进而一个操作系统必须具备进程隔离这个特性。在Linux系统中,虚拟内存机制为每个进程分配了线性连续的内存空间,操作系统将这种虚拟内存空间映射到物理内存空间,每个进程有自己的虚拟内存空间,进而不能操作其他进程的内存空间,每个进程只能操作自己的虚拟内存空间,只有操作系统才有权限操作物理内存空间.进程隔离保证了每个进程的内存安全,但是在大多数情形下,不同进程间的数据通讯是不可避免的,因此操作系统必须提供跨进程通信机制。
Android 几种进程通信方式
Android多进程通信的相关技术和方法网上有很多总结,因为其重要性,在学习这块相关内容时也显得非常重要,此时从网上搜索会发现总结了很多Binder、AIDL、ContentProvider、Socket等各种方法,看起来很高端很复杂的样子,但却导致无从下手,难以开始。因此,可以从Android四大组件入手,Activity,Service,BroadcastReceiver,ContentProvider
Activity
Activity既可以在进程内(同一个应用程序)访问,也可以跨进程访问。但Activity 的跨进程通信其实最为常见,就是我们经常使用的 Intent,通过startActivity的方式将Intent实例化并发送出去,此时启动的Acitivity很有可能是在不同进程中的,同时,配合startActivityForResult 和 onActivityResult 就解决了进程间通信的问题。
- 同一个应用程序中访问Activity:指定Context对象和Activity的Class对象
Intent intent = new Intent(this , Test.class );
startActivity(intent);
- Activity的跨进程访问:都需要Intent对象,但跨进程访问并不需要指定Context对象和Activity的Class对象,而需要指定的是要访问的Activity所对应的Action,有些Activity还需要指定一个Uri
Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel://13888888888" );
startActivity(callIntent);
Service
Service 的跨进程通信较为复杂,但主要的通信方式包括:Binder、Messenger、AIDL,他们的原理都是类似的,主要区别如下:
- 扩展Binder类:只在本App中使用,且与客户端运行在相同进程下;
- 使用Messenger:进程间通信,但不需要处理多线程;
- 使用AIDL:进程间通信,需要处理多线程操作;
Content Provider
ContentProvider为存储和获取数据提供统一的接口,它可以在不同的应用程序之间共享数据,本身就是适合进程间通信的。ContentProvider底层实现也是Binder,是对 SQLite 的一种封装,ContentProvider封装了跨进程共享的逻辑, 只需要Uri即可访问数据, 使用共享数据非常便捷,提供了一种数据的访问方式,可以对外提供或获取数据,如电话本、图片、短信等。
Broadcast Receiver
Broadcast Receiver 可以发送广播,例如APP1发送了一个广播,APP2监听该广播,并在监听到时对该广播进行响应处理,也达到了进程间通信的目的。广播跨进程通讯是一种被动的访问方式。当某个程序向系统发送广播时,其他的应用程序只能被动地接收广播数据。这就象电台进行广播一样,听众只能被动地收听,而不能主动与电台进行沟通。
其他方式
文件共享
Socket
Socket 通信实际上为,与Android系统本身没有太大关系,但在实际使用中需要注意端口分配映射关系的处理。
其中:
- Activity可以跨进程调用其他应用程序的Activity;
- Content Provider可以跨进程访问其他应用程序中的数据(以Cursor对象形式返回),当然,也可以对其他应用程序的数据进行增、删、改操 作;
- Broadcast可以向android系统中所有应用程序发送广播,而需要跨进程通讯的应用程序可以监听这些广播;
- Service和Content Provider类似,也可以访问其他应用程序中的数据,但不同的是,Content Provider返回的是Cursor对象,而Service返回的是Java对象,这种可以跨进程通讯的服务叫AIDL服务。
IPC适合场景及优缺点
名称 | 优点 | 缺点 | 使用场景 |
---|---|---|---|
Bundle | 简单易用 | 只能传输Bundle支持的数据类型 | 四大组件的进程间通信 |
AIDL | 功能强大,支持一对多的并发通信,支持实时通信 | 使用较复杂,需要处理好线程同步 | 一对多通信且有RPC需求 |
Messenger | 功能一般,支持一对多的穿行通信,支持实时通信 | 不能很好处理并发现象,不支持RPC,只能传输Bundle支持的数据类型 | 低并发的一对多即时通信,无RPC需求 |
ContentProvider | 数据访问方面功能强大,支持一对多并发数据共享 | 受约束的AIDL,主要提供数据源的CRDU操作 | 一对多的进程间的数据共享 |
文件共享 | 简单易用 | 不适合高并发场景,无法做到进程间的及时通信 | 没有并发的情形,交换简单的数据 |
Socket | 功能强大,可通过网络传输字节流,支持一对多的并发实时通信 | 繁琐,不支持直接的RPC | 网络数据交换 |