写笔记的初衷是为了根据书籍系统的学习Andorid知识与方便回顾


IPC机制概述

Android IPC介绍

IPC含义为进程间的通信或者跨进程通信,是指两个进程间进行数据交互(例如Android中读取系统的通讯录),平时我们开发中,接触线程比较多,但是进程却很少。其实我们时时刻刻都在运用进程,因为一个进程就是一个应用(默认情况下),一个进程可以包含很多个线程

Android中的多进程模式

开启多进程模式

Android开启多进程的方式基本只有在AndroidManifest上给四大组件指定android:process属性 来实现多进程,除此以外非常规的方法就是通过JNI在native层去fork一个新的进程

process属性命名的一些细节 ": remote" 其中":" 的含义是指要在当前的进程名前面加上包名,其次以":"开头的进程属于当前应用的私有进程,不以":"开头的进程属于全局进程。其他应用可以通过ShareUID 方式可以和它跑在同一个进程。

UID:一般理解为User Identifier,UID在linux中就是用户的ID,表明时哪个用户运行了这个程序,主要用于权限的管理。而在android 中又有所不同,因为android为单用户系统,这时UID 便被赋予了新的使命,数据共享,为了实现数据共享,android为每个应用几乎都分配了不同的UID,不像传统的linux,每个用户相同就为之分配相同的UID。(当然这也就表明了一个问题,android只能时单用户系统,在设计之初就被他们的工程师给阉割了多用户),使之成了数据共享的工具。

多进程模式的运行机制

多进程会造成的影响

  1. 静态成员和单利模式完全失效
  2. 线程同步机制完全失效
  3. SharedPreferences的可靠性下降
  4. Application 会多次创建

众所周知Android系统会为每一个应用分配一个独立的虚拟机或者进程,不同虚拟机在内存分配上有不同的地址空间,这就是导致在不同的虚拟机中访问同一个类会产生多分副本(静态,单利,同步机制),又因为这个机制,开启多进程之后application也会创建多次,而SharedPreferences底层是通过读/写 XML文件实现,并发是可能发生的.

IPC基础概念介绍

Serializable接口

Serializable接口是Java所提供的一个序列化接口,它是一个控接口,为对象提供序列化与反序列化的操作.

serialVersionUID 工作机制: 序列化的时候系统会把当前类的serialVersionUID 写入序列化文件中(也有可能时其他中介),当反序列化的时候系统会去检测文件中的serialVersionUID,看它是否和当前类的serialVersionUID 一致,如果一致就说明序列化的类的版本和当前版本时一致的,这个时候反序列化可以成功,否则就说明当前类的和序列化的类相比发生了某些板换,比如成员变量的数量,类型可能发生了该百年,这个时候无法正常的反序列化.

Parcelable接口

Parcelable接口时Android自带的一种序列化接口.

Parcel内部包装了可序列化的数据,可以在Binder中自由传输. 序列化过程中需要实现的功能有反序列化,序列化和内容描述.
序列化功能由WriteToParcel完成,通过Parcel一系列的write方法来完成,反序列化由CREATOR来完成,其内部标明了如何创建序列化对象和数组,并通过Parcel的一系列Read方法来完成反序列化的过程.内容描述则由describeContents方法完成,只有当有描述时返回为1,否则都为0;

Parcelable与Serializable区别

相同点:无论是Parcelable还是Serializable,执行反序列操作后的对象都是新创建的,与原来的对象并不相同,只不过内容一样罢了。
不同点:Serializable的设计初衷是为了序列化对象到本地文件、数据库、网络流、RMI以便数据传输,当然这种传输可以是程序内的也可以是两个程序间的。而Android的Parcelable的设计初衷是由于Serializable效率过低,消耗大,而android中数据传递主要是在内存环境中(内存属于android中的稀有资源),因此Parcelable的出现为了满足数据在内存中低开销而且高效地传递问题。

使用建议:Parcelable的性能比Serializable好,在内存开销方面较小,所以Android应用程序在内存间数据传输时推荐使用Parcelable,如activity间传输数据和AIDL数据传递,而Serializable将数据持久化的操作方便,因此在将对象序列化到存储设置中或将对象序列化后通过网络传输时建议选择Serializable(Parcelable也是可以,只不过实现和操作过程过于麻烦并且为了防止android版本不同而导致Parcelable可能不同的情况,因此在序列化到存储设备或者网络传输方面还是尽量选择Serializable接口

Binder

Binder为Android中的一个类,实现了IBinder接口,从IPC角度来收,Binder是Android中跨进程通信方式,Binder也可以理解为虚拟的物理设备,它的设备驱动是/dev/binder,该通信方式在Linux中没有,从Android Framework角度来说,Binder是ServiceManager连接各种Manager(ActivityManager,WindowManager,等)和相应ManagerService的桥梁;从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当BinderService时,服务端会返回一个包含了服务端业务调用的Binder对象,通过这个对象可以获取服务端提供的服务或者数据,这里的服务包括普通的业务逻辑服务和基于AIDL的服务

DESCRIPTOR

Binder的唯一标识,一般用于当前Binder的类名表示

asInterface

用于将服务端的Binder对象转换成客户端所需的AIDL接口对象,这种转换是区分进程的,客户端与服务端位于同一进程,那么此方法返回的就是服务端的Stub对象本身,否则返回的是系统封装过后的Stub.proxy对象

asBinder

用于返回当前的Binder对象

onTransact

这个方法运行在服务端中的Binder线程池中,此方法只会在跨进程的时候调用,此方法返回false,那么客户端请求会失败,因此我们可以利用这个特效来做权限验证. 服务端可以通过参数code来确定客户端所请求的目标方法,接着可以从data中取出目标方法所需的参数,当目标方法执行完毕之后,就向reply中写入返回值.

linkToDeath和unLickToDeath 是用来对应 当服务端进程由于某种原因异常终止,这个时候服务端的Binder断裂,导致远程调试失败,而我们不知道这种情况, 这时候使用linkToDeath和unLickToDeath就可以监听到,然后重新绑定服务

Android中IPC方式

使用Bundle

由于Bundle实现了Parcelable接口,所有它可以方便在不同的进程中传输。不过我们传输的数据必须能被序列化,比如基本类型。实现了Parcelable接口的对象,实现了Serializable接口的对象以及一些Android支持的特殊对象

使用文件共享

文件共享是通过两个进程通过读/写同一个文件来交换数据,因为Android系统基于Linux,使得其并发读/写文件可以没有限制的进行,甚至两个线程同时对同一个文件进行操作也允许。

反序列化得到的对象只是内容和序列化之前的对象是一样的,但本质是两个对象

文件共享IPC适合对数据同步要求不高的进程之间进行通信,并且要妥善处理并发读/写问题

使用Messenger

Messenger是一种轻量级的IPC方案,它的底层实现是AIDL。

private static class MessengerHandler extends Handler{       `````       `````       `````}private final Messenger mMeesenger = new Messenger(new MessengerHandle())@Overridepublic IBinder onBind(Intent intent){  return mMessenger.getBinder();}

然后在client端 通过Bundle 来进行IPC数据传输

Message中的object 字段 在2.2之前不支持跨进程传输,2.2之后也 支持Parcelable接口的对象才能通过它传输
所有我们可以使用Messenger.setData 来使用Bundle传输

在不同进程中通过msg.replyTo来获取另一端的Messenger对象

Messenger它一次处理一个请求。所有建议少量请求时使用

使用AIDL

AIDL文件支持的数据类

  1. 基本数据类型
  2. String和CharSequence
  3. LIst: 只支持ArrayList
  4. Map: 只支持HashMap
  5. Parcelable:所有实现Parcelable接口对象
  6. AIDL: 所有AIDL接口本身也可以AIDL文件

自定义的Parcelable和AIDL对象必须显性的import进来。

AIDL中除了基本数据类型,其他类型的参数必须标上方向:in. out或者inout,in 表示输入型参数,out表示输出型参数,inout表示输入输出型参数.

CopyOnWriteArrayList 支持并发读写,AIDL方法时在服务端的Binder线程池中执行的,因此多个客户端同时连接,会存在多个线程同时访问的情形,所有我们要在AIDL方法中处理线程同步,CopyOnWriteArrayList来进行自动线程同步

在客户端注册和解除时传递的对象 时不能跨进程的,如果没有注意到这一点会导致无法注解,对象跨进程传输本质上反序列化的过程,这就是AIDL中自定义对象必须实现Parcelable接口的原因,我们可以通过RemoteCallbackList系统专门提供的用删除跨进程的接口。

客户端调用远程服务的方法,被调用的方法运行在服务端的Binder线程池中,客户端线程会被挂起,这个时候服务端方法比较耗时时,会导致客户端线程长时间阻塞,所有要避免客户端UI线程去访问远程方法。 而AIDL方法会在服务线程中执行,所有进行耗时操作。

使用ContenProvider

ContentProvider 是Android提供专门不同应用数据共享的方式,天生自带跨进程通信,呵Messenger一样,ContentProvider底层是Binder. (具体实现看书上)

使用Socket

Socket称为(套接字),为网络通信的概率,它分为流式套接字和用户数据报套接子两种,分别对应网络传输控制的TCP和UDP。
(具体实现看书上)

Binder连接池

一个Service对应多个AIDL文件的解决方案 具体看书()

不同IPC的比较

名称优点缺点适用场景
Bundle简单易用只能传输Bundle支持的数据类型四大组件间的进程间的通信
文件共享简单易用不适合高并发场景,并且无法做到进程间的即使通信无并发访问情形,交换简单的数据实时性不高的场景
AIDL功能强大,支持一对多并发通信,支持实时通信使用稍复杂,需要处理好线程同步一对多通信且有RPC(远程)需求
Messenger支持一对多串行通信,支持实时通信不能很好的处理高并发情形,不支持RPC,数据通过Message进行传输,因此只能传输Bundle支持的数据类型低并发一对多即使通信,无RPC需求,或者无须要返回结果的RPC需求
ContentProvider在数据源访问方面功能强大,支持一对多并发数据共享,可通过Call方法扩展其他操作可以理解为受约束的AIDL,主要提供数据源的CRUD操作一对多的进程间的共享数据
Socket通过网络传输字节流,支持一对多并发实时通信实现细节稍微有点繁琐,不支持直接的RPC网络数据交换

更多相关文章

  1. 一款霸榜 GitHub 的开源 Linux 资源监视器!
  2. android离开一个页面时关闭子线程
  3. iOS到Android到底有多远
  4. Android(安卓)重要基本开发规范
  5. Android内存泄露浅析
  6. android ContentProvider实现跨进程文件传输
  7. Android(安卓)中内存泄漏的原因分析及解决方案
  8. Android进程通信Binder(1)-Binder进程通信的思想
  9. 都在说EventBus,我也来一波EventBus

随机推荐

  1. 如果字符串包含html代码,如何用python检测
  2. 去除Chrome浏览器文本框边缘的黄线
  3. 【竞价网站绝技】根据访客ip,页面显示访客
  4. Html css缩放会将大小改变几个像素
  5. 利用HTML5开发Android笔记
  6. J2EE进阶之onsubmit表单提交 五
  7. j2ee的web项目,有最终的html代码(即f12看到
  8. 仅使用CSS / HTML将鼠标悬停在按钮上时显
  9. 如何截取html的子字符串作为内容摘要
  10. vs远程调试 转http://www.cnblogs.com/ma