学习笔记 | Android开发艺术之IPC机制

知识储备
 a. IPC(Inter-Process Communication):进程间通信或者跨进程通信,是指两个进程之间进行数据交换的过程。
 b. 线程:CPU调度的最小单元,是一种有限的系统资源。
 c. 进程:一般指一个执行单元,在PC和移动设备上指一个程序或者一个应用。一个进程可以包含多个线程。
 d. ANR(Application Not Responding):应用无响应。

一、Android中的多进程模式

(1). 开启多进程模式的方式

 a. 给四大组件在AndroidMenifest中指定android:process属性(常用)

区别:android:process=":remote"android:process="com.ryg.chapter_2.remote"

  • “:”的含义是指要在当前的进程名前面附加上当前的包名,简写方法。
  • 进程名以“:”开头的进程属于当前应用的私有进程,其他应用的组件不可以和它跑在同一个进程中。
  • 进程名不以“:”开头的进程属于全局进程,其他应用通过ShareUID(要求:两个应用有相同的ShareUID并且签名相同)方式可以和它跑在同一个进程中。

    b. 通过JNI在native层去fork一个新的进程(不常用)

(2)查看进程信息的方法

  • 通过DDMS视图查看进程信息
  • 通过shell查看,命令为:adb shell ps|grep 包名

(3)多进程造成的问题

 a. 静态成员和单例设计模式失效
 运行在不同进程中的四大组件,需要通过内存来共享数据,但不同进程的内存区域不一样。

 b. 线程同步机制失效
 原因类似,无法锁对象或者类。

 c. SharedPreferences 可靠性下降
 因为SharedPreferences底层是通过读写XML文件实现的,不支持多个进程的并发操作。

 d. Application 多次创建
 系统要在创建新的进程同时分配独立的虚拟机,相当于把这个应用重新启动了一遍,那么自然会创建新的Application(运行在同一个进程中的组件是属于同一个虚拟机和同一个Application的,同理,运行在不同进程中的组件是属于两个不同的虚拟机和Application的)。

二、IPC基础概念

(1)序列化

a. 序列化:由于存在于内存中的对象都是暂时的,无法长期驻存,为了把对象的状态保持下来,这时需要把对象写入到磁盘或者其他介质中,这个过程就叫做序列化。

b. 反序列化:把已存在在磁盘或者其他介质中的对象,反序列化(读取)到内存中,以便后续操作,而这个过程就叫做反序列化。

c. Serializable接口和Parcelable接口
 任务:为对象提供标准的序列化和反序列化操作
 区别:

SerializableParcelable
平台Java中的序列化接口Android中的序列化接口
实现原理将一个对象转换成可存储或可传输的状态将一个完整的对象进行分解, 而分解后的每一部分都是Intent所支持的数据类型
实现方式只需要implements Serializable 即可不仅需要implements Parcelabel,还需要在类中添加一个静态成员变量CREATOR,这个变量需要实现 Parcelable.Creator 接口
性能创建了大量临时对象,造成垃圾回收效率高
适用场景把对象持久化到存储设备上或者通过网络传输给其他客户端主要用在内存序列化上
读写数据的方式通过使用IO流的形式将数据读写入在硬盘上在内存中直接进行读写

d. Parcelable的方法说明:

  • 序列化功能由writeToParcel方法来完成,最终是通过Parcel中的一系列write方法来完成的;
  • 反序列化功能由CREATOR来完成,其内部标明了如何创建序列化对象和数组,并通过Parcel的一系列read方法来完成反序列化过程;
  • 内容描述功能由describeContents方法来完成,几乎在所有情况下这个方法都应该返回0,仅当当前对象中存在文件描述符时,此方法返回1。

e. serialVersionUID

  • 含义:是Serializable接口中用来辅助序列化和反序列化过程。
  • 不参与序列化过程的情况:(1)静态成员变量属于类不属于对象;(2)用transient关键字标记的成员变量。
  • 注意:(1)原则上序列化后的数据中的serialVersionUID要和当前类的serialVersionUID 相同才能正常的序列化。(2)手动指定serialVersionUID可以在很大程度上避免反序列化过程的失败。

(2)Binder

a. 概念
Binder是Android中的一种跨进程通信方式,是客户端和服务端进行通信的媒介。

b. 工作原理:

  • 服务器端:在服务端创建好了一个Binder对象后,内部就会开启一个线程用于接收Binder驱动发送的消息,收到消息后会执行onTranscat(),并按照参数执行不同的服务端代码。
  • Binder驱动:在服务端成功Binder对象后,Binder驱动也会创建一个mRemote对象(也是Binder类),客户端可借助它调用transcat()即可向服务端发送消息。
  • 客户端:客户端要想访问Binder的远程服务,就必须获取远程服务的Binder对象在Binder驱动层对应的mRemote引用。当获取到mRemote对象的引用后,就可以调用相应Binder对象的暴露给客户端的方法。

c. Server端拥有的是Binder的实体;Client端拥有的是Binder的引用

推荐阅读:Android跨进程通信:图文详解 Binder机制 原理

(3)Android中的IPC方式

方式说明补充
Bundle实现了Parcelable接口,支持在Activity、Service和Receiver之间通过Intent.putExtra()传递Bundle数据
文件共享两个进程通过读/写同一个文件来交换数据。比如A进程把数据写入文件,B进程通过读取这个文件来获取数据
Messenger在Message中放入需要传递的数据,通过Messenger在不同进程中传递Message对象实现数据的进程间传递以串行的方式处理客户端发来的消息,AIDL是Messenger的底层实现所以Messenger本质上也是AIDL
AIDL如果在一个进程中要调用另一个进程中对象的方法,可使用AIDL生成可序列化的参数,AIDL会生成一个服务端对象的代理类,通过它客户端实现间接调用服务端对象的方法AIDL的包结构在服务端和客户端要保持一致;AIDL方法是在服务端的Binder线程池中执行的
ContentProvider屏蔽了数据存储的细节,内部实现对用户完全透明,用户只需要关心操作数据的 uri 就可以了,专门用于不同应用间进行数据共享的方式。底层同样是通过Binder实现的
Socket“套接字”,分为流式套接字和用户数据报套接字两种流套接字:基于TCP协议,采用流的方式提供可靠的字节流服务。 数据报套接字:基于UDP协议,采用数据报文提供数据打包发送的服务。

推荐阅读:Binder,AIDL和Messenger的原理及使用流程

AIDL(Android Interface Definition Language)

 a. AIDL的本质是系统提供了一套可快速实现Binder的工具。关键类和方法:

AIDL接口:继承IInterface。

Stub类:Binder的实现类,服务端通过这个类来提供服务。

Proxy类:服务器的本地代理,客户端通过这个类调用服务器的方法。

asInterface():客户端调用,将服务端的返回的Binder对象,转换成客户端所需要的AIDL接口类型对象。返回对象:

  • 若客户端和服务端位于同一进程,则直接返回Stub对象本身;
  • 否则,返回的是系统封装后的Stub.proxy对象。

asBinder():根据当前调用情况返回代理Proxy的Binder对象。

onTransact():运行服务端的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法来处理。

transact():运行在客户端,当客户端发起远程请求的同时将当前线程挂起。之后调用服务端的onTransact()直到远程请求返回,当前线程才继续执行。
原理图
 b. 实现方法

  • 服务端:
    创建一个aidl文件;
    创建一个Service,实现AIDL的接口函数并暴露AIDL接口。
  • 客户端:
    通过bindService绑定服务端的Service;
    绑定成功后,将服务端返回的Binder对象转化成AIDL接口所属的类型,进而调用相应的AIDL中的方法。
    推荐文章:AIDL

 c. AIDL 解注册失败

  • 原因:Binder进行对象传输实际是通过序列化和反序列化进行,即Binder会把客户端传递过来的对象重新转化并生成一个新的对象,虽然在注册和解注册的过程中使用的是同一个客户端对象,但经过Binder传到服务端后会生成两个不同的对象。另外,多次跨进程传输的同一个客户端对象会在服务端生成不同的对象,但它们在底层的Binder对象是相同的。
  • 解决办法:当客户端解注册的时候,遍历服务端所有的Listener,找到和解注册Listener具有相同的Binder对象的服务端Listener,删掉即可。
ContentProvider

 a. 自定义ContentProvider的步骤
 步骤一:新建一个类去继承ContentProvider。
 步骤二:重写ContentProvider的六个抽象方法:onCreate、query、update、insert、delete和getType。

  • onCreate代表ContentProvider的创建,做一些初始化工作
  • getType用来返回一个Uri请求所对应的MIME类型(媒体类型),比如图片、视频等,如果我们的应用不关注这个选项,可以直接在这个方法中返回null或者“/
  • 剩下的四个方法对应于CRUD操作,即实现对数据表的增删改查功能。

 步骤三:在配置文件中进行注册,并注明属性:
android:authorities即Provider的权限,形式是包名.provider
android:name即Provider的全名,形式是包名.类名
android:exported="true"指明该Provider可被其它程序访问。

 b. 组织数据方式
 ContentProvider主要以表格的形式来组织数据,并且可以包含多个表。

 c. 注意

  • 除了onCreat()运行在UI线程中,其他的query()、update()、insert()、delete()和getType()都运行在Binder线程池中。
  • CRUD四大操作存在多线程并发访问,要注意在方法内部要做好线程同步。
  • 一个SQLiteDatabase内部对数据库的操作有同步处理,但多个SQLiteDatabase之间无法同步。
  • ContentProvider类并不会直接与外部进程交互,而是通过ContentResolver 类。

 d. ContentProvider 、 ContentResolver 、 ContentObserver 之间的关系

  • ContentProvider 内容提供者,用于对外提供数据
  • ContentResolver.notifyChange(uri)发出消息
  • ContentResolver 内容解析者,用于获取内容提供者提供的数据
  • ContentObserver 内容监听器,可以监听数据的改变状态
  • ContentResolver.registerContentObserver()监听消息。

推荐阅读:ContentProvider的知识

Socket

Socket连接过程Socket连接过程
推荐阅读:Android:这是一份很详细的Socket使用攻略

(4)Binder连接池
在这里插入图片描述实现方式:

  • 为每个业务模块创建AIDL接口并具体实现
  • 为Binder连接池创建AIDL接口IBinderPool.aidl并具体实现
  • 远程服务BinderPoolService的实现,在onBind()返回实例化的IBinderPool实现类对象
  • Binder连接池的具体实现,来绑定远程服务
  • 客户端的调用
    推荐阅读:Binder小结以及Binder连接池
         Binder连接池
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值