1、IPC基础及概念html
1.多进程模式java
a.进程&线程linux
二者关系: 一个进程可包含多个线程,即一个应用程序上能够同时执行多个任务。android
- 主线程(UI线程):UI操做
- 有限个子线程:耗时操做
注意:不可在主线程作大量耗时操做,会致使ANR(应用无响应)。git
b.开启多进程模式的方式:shell
android:process
,进程名的命名规则:
android:process=":remote"
,表示进程名为com.example.myapplication:remote
。android:process="com.example.myapplication.remote"
。UID&ShareUID:数据库
- Android系统为每一个应用分配一个惟一的UID,具备相同UID的应用才能共享数据。
- 两个应用经过ShareUID跑在同一进程的条件:ShareUID相同且签名也相同。
- 知足上述条件的两个应用,不管是否跑在同一进程,它们可共享data目录,组件信息。
- 若跑在同一进程,它们除了可共享data目录、组件信息,还可共享内存数据。它们就像是一个应用的两个部分。
c.查看进程信息的方法:缓存
adb shell ps|grep 包名
。d.须要进程间通讯的必要性:全部运行在不一样进程的四大组件,只要它们之间须要经过内存在共享数据,都会共享失败。安全
缘由:因为Android为每一个应用分配了独立的虚拟机,不一样的虚拟机在内存分配上有不一样的地址空间,这会致使在不一样的虚拟机中访问同一个类的对象会产生多份副本。bash
e.多进程形成的影响,总结为如下四方面:
①静态变量和单例模式失效。
②线程同步机制失效。
③SharedPreference的不可靠降低。
④Application屡次建立。
推荐阅读:关于Android多进程
2.序列化
a.序列化的介绍
- 含义:序列化表示将一个对象转换成可存储或可传输的状态。序列化后的对象能够在网络上进行传输,也能够存储到本地。
- 场景:须要经过Intent和Binder等传输类对象就必须完成对象的序列化过程。
- 两种方式:实现Serializable/Parcelable接口。
b.Serializable接口和Parcelable接口的比较:
c.serialVersionUID
注意:两种变量不会参与序列化过程:
- 静态成员变量属于类,不属于对象。
- 用transient关键字标记的成员变量。
推荐阅读:序列化Serializable和Parcelable的理解和区别
3.IPC简介
a.IPC(Inter-Process Communication,跨进程通讯):指两个进程之间进行数据交换的过程。
b.任何一个操做系统都有对应的IPC机制。
c.IPC的使用场景:
d.Android的进程架构:每个Android进程都是独立的,且都由两部分组成,一部分是用户空间,另外一部分是内核空间,以下图:
如此设计的优势:
4.Binder机制
a.概念:
b.Android是基于Linux内核基础上设计的,却没有把管道/消息队列/共享内存/信号量/Socket等一些IPC通讯手段做为Android的主要IPC方式,而是新增了Binder机制,其优势有:
方式 | 拷贝次数 | 操做难度 |
---|---|---|
Binder | 1 | 简易 |
消息队列 | 2 | 简易 |
Socket | 2 | 简易 |
管道 | 2 | 简易 |
共享内存 | 0 | 复杂 |
从Android进程架构角度分析:对于消息队列、Socket和管道来讲,数据先从发送方的缓存区拷贝到内核开辟的缓存区中,再从内核缓存区拷贝到接收方的缓存区,一共两次拷贝,如图:
而对于Binder来讲,数据从发送方的缓存区拷贝到内核的缓存区,而接收方的缓存区与内核的缓存区是映射到同一块物理地址的,节省了一次数据拷贝的过程,如图:
因为共享内存操做复杂,综合来看,Binder的传输效率是最好的。
实现C/S架构方便:Linux的众IPC方式除了Socket之外都不是基于C/S架构,而Socket主要用于网络间的通讯且传输效率较低。Binder基于C/S 架构 ,Server端与Client端相对独立,稳定性较好。
安全性高:传统Linux IPC的接收方没法得到对方进程可靠的UID/PID,从而没法鉴别对方身份;而Binder机制为每一个进程分配了UID/PID且在Binder通讯时会根据UID/PID进行有效性检测。
c.Binder框架定义了四个角色:Server,Client,ServiceManager和Binder驱动。
其中Server、Client、ServiceManager运行于用户空间,Binder驱动运行于内核空间。关系如图:
下面简单介绍这四个角色:
d.代理模式Proxy:给某个对象提供一个代理对象,并由代理对象控制对原对象的访问。如图:
代理模式的组成:
推荐阅读:代理模式
e.Binder 工做原理:
后面会经过AIDL和Messager更深入地体会这一工做原理。
推荐阅读:Android - Binder驱动、Binder设计与实现、Binder系列、
3、IPC方式
由上图能够看到,其余一些IPC方式实际都是经过Binder来实现,只不过封装方式不一样。接下来分别总结其余六种IPC方式:
1.使用Bundle
a.Bundle:支持在Activity、Service和Receiver之间经过**Intent.putExtra()**传递Bundle数据。
Intent intent = new Intent();
Bundle bundle = new Bundle();
bundle.putString("xxx","xxx");
intent.putExtra("data", bundle);
复制代码
b.原理:Bundle实现Parcelable接口,它可方便的在不一样的进程中传输。
c.注意:Bundle不支持的数据类型没法在进程中被传递。
思考下面这种状况: Q:在A进程进行计算后的结果不是Bundle所支持的数据类型,该如何传给B进程? A:将在A进程进行的计算过程转移到B进程中的一个Service里去作,这样可成功避免进程间的通讯问题。
推荐阅读:经过Bundle在Android Activity间传递数据
2.使用文件共享
a.文件共享:两个进程经过读/写同一个文件来交换数据。好比A进程把数据写入文件,B进程经过读取这个文件来获取数据。
b.适用状况:对数据同步要求不高的进程之间进行通讯,而且要妥善处理并发读/写的问题。
c.虽然SharedPreferences也是文件存储的一种,但不建议采用。
3.使用AIDL
a.AIDL(Android Interface Definition Language,Android接口定义语言):若是在一个进程中要调用另外一个进程中对象的方法,可以使用AIDL生成可序列化的参数,AIDL会生成一个服务端对象的代理类,经过它客户端实现间接调用服务端对象的方法。
b.可支持的数据类型:
注意:除了基本数据类型,其它类型的参数必须标上方向:in、out或inout,用于表示在跨进程通讯中数据的流向。
- in
- 表示数据只能由客户端流向服务端。
- 服务端将会接收到这个对象的完整数据,但在服务端修改它不会对客户端输入的对象产生影响。
- out
- 表示数据只能由服务端流向客户端。
- 服务端将会接收到这个对象的的空对象,但在服务端对接收到的空对象有任何修改以后客户端将会同步变更。
- inout
- 表示数据可在服务端与客户端之间双向流通。
- 服务端将会接收到客户端传来对象的完整信息,且客户端将会同步服务端对该对象的任何变更。
c.两种AIDL文件:
注意:
- 自定义的Parcelable对象必须把java文件和自定义的AIDL文件显式的import进来,不管是否在同一包内。
- AIDL文件用到自定义Parcelable的对象,必须新建一个和它同名的AIDL文件,并在其中声明它为Parcelable类型。
d.AIDL的本质是系统提供了一套可快速实现Binder的工具。关键类和方法:
经过此处实例具体了解AIDL实现IPC的流程:
推荐阅读:Android中AIDL的工做原理
e.实现方法:
总结:服务端里的某个Service给和它绑定的特定客户端进程提供Binder对象,客户端经过AIDL接口的静态方法asInterface() 将Binder对象转化成AIDL接口的代理对象,经过这个代理对象就能够发起远程调用请求。
f.可能产生ANR的情形:
g.解决客户端频繁调用服务器方法致使性能极大损耗的办法:实现观察者模式。即当客户端关注的数据发生变化时,再让服务端通知客户端去作相应的业务处理。
好比:每一个客户端的请求Listener传递给服务端,服务端用一个list保存,当数据变化时服务器再依次通知,此时客户端就用Listener进行回调处理。注意要用Handler切换到主线程。
h.AIDL 解注册失败
须要用到RemoteCallBackList:Android系统专门提供的用于删除跨进程listener的接口。其内部自动实现了线程同步的功能。
4.使用Messager
a.Messenger:轻量级的IPC方案,经过它可在不一样进程中传递Message对象。
Messenger.send(Message);
复制代码
相关记忆:
- Handler:主要进行线程间的数据通讯。
- Messenger:进程间的数据通讯。
b.特色:
c.实现方法:
d.Message的缺点:
解决办法:考虑使用AIDL实现IPC。
推荐阅读:超简单的Binder,AIDL和Messenger的原理及使用流程
5.使用ContentProvider
a.ContentProvider:是Android提供的专门用来进行不一样应用间数据共享的方式。
底层一样是经过Binder实现的。
b.注意:
基础篇: 组件篇之ContentProvider
6.使用Socket
a.Socket(套接字):不只可跨进程,还能够跨设备通讯。
b.使用类型
c.实现方法:TCP/UDP
d.注意:使用Socket进行通讯
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
复制代码
推荐阅读:这是一份很详细的Socket使用攻略
综上,以上六种IPC方式的优缺点和使用场景见下图:
四.Binder链接池
a.背景:有多个业务模块都须要AIDL来进行IPC,此时须要为每一个模块建立特定的aidl文件,那么相应的Service就会不少。必然会出现系统资源耗费严重、应用过分重量级的问题。
b.做用:将每一个业务模块的Binder请求统一转发到一个远程Service中去执行,从而避免重复建立Service。
c.工做原理:每一个业务模块建立本身的AIDL接口并实现此接口,而后向服务端提供本身的惟一标识和其对应的Binder对象。服务端只须要一个Service,服务器提供一个queryBinder接口,它会根据业务模块的特征来返回相应的Binder对像,不一样的业务模块拿到所需的Binder对象后就可进行远程方法的调用了。流程如图:
d.实现方式:
实例:细说Binder链接池
如今能够回答如下问题:
Q:在Android开发中提升开发效率的方法?
A:使用Binder链接池,避免反复建立Service,统一管理和维护AIDL。
推荐阅读:Android的IPC机制、Android跨进程通讯IPC
但愿这篇文章对你有帮助~