文章目录
第2章 IPC机制
2.1 Android IPC 简介
- IPC 是 Inter-Process Communication 的缩写,进程间通信或跨进程通信,两个进程之间进行数据交换过程。
- 进程:系统进行资源分配和调度的基本单位。
- 线程:CPU 调度的最小单元。
- Binder:Android 特色的进程通信方式。
- 应用场景
1.应用某些业务场景需要自身采用多进程模式,例如有些模块需要运行在单独进程中,视频播放等。
2.当前应用需要向其他应用获取数据,典型的 ContentProvider 就是一种跨进程通讯。
2.2 Android 中的多进程模式
2.2.1 开启多进程模式
- 使用方式只有一种:四大组件在 AndroidMenifest 中指定 android:process 属性(特殊:通过 JNI 在 native 去 fork 一个新进程)
1.android:process=":remote"(: 含义,1.在当前的进程名前面附加当前包名,最后结果 com.ryg.chapter_2:remote;2.该进程属于私有进程)
2.android:process=“com.ryg.chapter_2.remote”(全局进程,其他应用通过 ShareUID 中可以跑在一个进程中) - Android 系统会为每个应用分配一个唯一的 UID,相同的 UID 进程才能共享数据。
2.2.2 多进程模式的运行机制
- 多进程造成问题
1.静态成员和单例模式完全失效
2.线程同步机制完全失效
3.SharedPreference 的可靠性下降
4.Application 会多次创建
2.3 IPC 基础概念介绍
2.3.1 Serializable 接口
- 是 Java 提供一个序列化接口,提供序列化和反序列化
- ObjectOutputStream 和 ObjectInputStream 实现
//序列化
User user = new User();
user.setName("Android");
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("cache.text"));
out.writeObject(user);
out.close();
//反序列化
ObjectInputStream in = new ObjectInputStream(new FileInputStream("cache.text"));
user = (User) in.readObject();
in.close();
- serialVersionUID 作用:值相同才能正常序列化和反序列化。
- 使用 transient 标记不参与序列化过程。
2.3.2 Parcelable
- 使用插件生成,简化操作
- 不同
Serializable | Parcelable |
---|---|
java 中的序列化结构 | Android 序列化接口 |
需要大量 I/O 操作,适用于本地存储和网络传输 | 用于内存序列化上 |
2.3.3 Binder
-
Binder 是 Android 一个类,实现 IBinder 接口
-
IPC 角度看,是Android中一种跨进程通讯方式
-
一种虚拟物理设备,设备驱动是/dev/binder
-
AndroidFramework 来看,ServiceManager 连接各种 Manager(ActivityManager、WindowManager) 和相应 ManagerService 的桥梁
-
应用层看,Binder 是客户端 和服务器进行通信的媒介。当 bindService 时,服务端返回一个包含服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务器端提供的服务或者数据( 包括普通服务和基于AIDL的服务)。
-
参考阅读:Binder系列
-
Android 开发中,Binder 主要用于 Seriver中,包括 AIDL 和 Messenger。
-
书中例子
1.DESCRIPTOR
Binder的唯一标识,一般用Binder的类名表示。
2.asInterface(android.os.IBinder obj)
将服务端的Binder对象转换为客户端所需的AIDL接口类型的对象,如果C/S位于同一进
程,此方法返回就是服务端的Stub对象本身,否则返回的就是系统封装后的Stub.proxy对
象。
3.asBinder
返回当前Binder对象。
4.onTransact
运行在服务端的Binder线程池中,由客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法来处理系统底层封装后交由此方法来处理
5.Proxy#getBookList 和Proxy#addBook
运行在客户端 -
AIDL 文件不是必须的,之所以提供AIDL文件,是为了方便系统为我们生成IBookManager.java,但我们完全可以自己写一个
-
注意:
1.客户端发起远程请求,当前线程会被挂起直到服务端进程返回数据。
2.服务端Binder方法运行中 Binder 线程池中,所以Binder 方法不管耗时都应采取同步方式实现。
- 服务器的 Binder 连接断裂(Binder 死亡)
- 死亡代理
1.linkToDeath
2.unlinkToDeath
3.使用:DeathRecipient
2.4 Android 中的 IPC 方式
2.4.1 使用 Bundle
- Bundle 实现了 Parcelable
2.4.2 使用文件共享
- SharedPreferences 属于文件一种,通过键值对方式来存储数据,采用 XML 文件来存储键值对,但是系统对它的读/写有一定的缓存策略,在内存找那个会有一份 sp 的缓存,在多进程模式下,变得不可靠
2.4.3 使用 Messenger
- 翻译信使,通过它可以在不同进程中传递 Message 对象,是一种轻量级 IPC 方案,底层是 AIDL。
1.服务端进程
创建一个 Service 来处理客户端连接请求,同时创建一个 Handler,并通过它创建一个 Messenger,在 Service 的 onBind 返回这个 Messenger 底层的 Binder
2.服务端进程
绑定服务端 Service,用服务端返回的 IBinder 对象创建一个 Messenger,通过这个 Messenger 就可以向服务器发送消息,如果需要服务器能够回应客户端,还需要创建一个 Handler 并创建一个新的 Messenger,这个 Messenger 对象通过 Message 的 replTo 传递给服务器。
2.4.4 使用 AIDL
-
步骤
1.服务器
创建一个 Service 监听客户端请求,创建一个 AIDL 文件,将暴露给客户端的接口在这个 AIDL 声明,在 Service 中实现这个 AIDL。
2.客户端
绑定服务端的 Service,将服务端返回的 Binder对象转成 AIDL 接口所属类型。
3.AIDL 接口的创建 -
AIDL 支持类型
1.基本数据类型
2.String 和 CharSequence
3.List,仅 ArrayList
4.Map,仅 HashMap
5.Parcelable
6.AIDL -
RemoteCallbackList:专门提供用于删除跨进程 listener 的接口,是一个泛型,支持管理任意的 AIDL 接口。beginBroadcast 和 finishBroadcast 必须配对使用。
-
Binder 死亡
1.DeadthRecipient
Binder 线程池
2.onServiceDisconnected
UI 线程 -
AIDL 使用权限
1.permission 验证(onBind 中)
2.onTransact,失败就直接返回 false
permission、Uid 和 Pid 验证
2.4.5 使用 ContentProcider
- 使用 Binder
- onCreate(主线程中)、query、update、insert、delete、getType(Binder 线程池中,用来返回一个 Uri 请求所对应的 MIME 类型)
- ContentResolver:观察 ContentProvider 数据发生改变
2.4.6 使用 Socket
- Socket 称为 套接字,分为流式套接字和数据报套接字
2.5 Binder 连接池
- AIDL
1.创建一个 Service 和 AIDL 接口
2.创建一个类继承 AIDL 接口中 Stub 类并实现 Stub 中的抽象方法
3.在 Service 的 onBind 方法返回这个类对象
4.客户端绑定 Service - Binder 连接池