您的位置:首页 > 移动开发 > Android开发

# 读 Android 开发艺术探索 &2

2017-02-06 11:26 519 查看
关键词:IPC / 多进程 / 序列化 / Binder

IPC,Inter-Process Communication 的缩写,含义为进程间通信或者跨进程通信,两个进程之间进行数据交换的过程。说到 IPC 的使用场景,就要提到多进程,当采用了多进程的设计方法,那么应用中就必须妥善处理进程间通信的各种问题。

[ 首先必须知道的几点:]

进程:一般是指一个执行单元,在 PC 和移动设备中指一个程序或者一个应用。

线程:CPU 调度的最小单元,是一种有限的系统资源。

一个进程可以包含多个线程,包含与被包含的关系。

一个进程可只有一个线程,主线程,在 Android 中就是 UI 线程,只有在 UI 线程里才能对界面元素进行操作。

ANR,Application Not Responding,应用无响应,防止ANR,把耗时的任务放在子线程中执行。

Android 有自己的进程间通信方式:Binder / Socket

通过系统提供的 ContentProvider 去查询数据的时候也是一种进程间通信,只不过通信细节被系统屏蔽了。

1. Android 中的多进程模式 #

在 Android 中使用多进程的常用方法只有一种:给四大组件在 AndroidManifest 中指定 android:process 属性。示例:

<activity android:name="io.github.isayes.MainActivity"
... />
<activity android:name="io.github.isayes.SecondActivity"
android:process=":remote" />
<activity android:name="io.github.isayes.ThirdActivity"
android:process="io.github.isayes.remote" />


[ 需要知道以下几点:]

启动 SecondActivity 的时候系统会为它创建一个单独的进程:“io.github.isayes:remote”;

启动 ThirdActivity 的时候系统为它创建一个单独的进程:“io.github.isayes.remote”;

入口的 MainActivity 运行在默认的进程中,默认的进程名为包名;

进程名以 “:” 开头说明进程属于当前应用的私有进程(其它应用的组件不可以与之跑在同一个进程中),不以之开头的进程是全局进程(其它应用通过 ShareUID 方式与之可以跑在同一个进程中);

Android 系统会为每个应用分配一个唯一的 UID,UID 相同才能共享数据(data 目录、组件信息等私有数据);UID 相同并且签名相同才能跑在同一个进程中(还可以共享内存数据)。

Android 系统为每一个应用分配了一个独立的虚拟机,或者说为每一个进程都分配了一个独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,导致在不同的虚拟机中访问同一个类的对象会产生多份副本。一般来说,使用多线程会导致以下几个需要注意的问题 ↓

静态成员和单例模式失效

线程同步机制失效

SharedPreferences 的可靠性下降

Application 会多次创建(运行在同一个进程中的组件是属于同一个虚拟机和同一个 Application 的,同理,运行在不同的进程中的组件是属于不同的两个虚拟机和不同的 Application )

在多进程模式中,不同的进程的组件会有独立的虚拟机,独立的Application 以及内存空间;

理解同一个应用间的多进程:相当于两个不同的应用采用了 ShareUID 的模式。

为了解决多进程带来的问题,系统提供了很多跨进程通信的方法,虽然不能直接的共享内存,但是通过跨进程通信可以实现数据交互。实现跨进程通信的方式有:

1. 通过 Intent 传递数据

2. 共享文件

3. SharedPreferences

4. 基于 Binder 的 Messenger 和 AIDL

5. Socket 等

要理解 IPC 的各种方式,需要熟悉一些基础概念:序列化相关的 Serializable / Parcelable 接口 和 Binder

2. IPC 基础 相关概念 #

IPC 的基础概念有三点:
Serializable
Parcelable
Binder
Serializable 和 Parcelable 接口完成对象的序列化过程,当我们通过 Intent 和 Binder 传输数据时就需要使用 Parcelable 或者 Serializable。

若需要把对象持久化到存储设备上或者通过网络传输给其他客户端,这时候也需要使用 Serializable 来完成对象的持久化。

【关于 Serializable 需要知道的几点】

Java 提供的序列化接口,是一个空接口

为对象提供标准的序列化和反序列化操作

几乎所有的工作都被系统自动完成了

静态成员变量属于类不属于对象,所以不会参与序列化过程

采用 transient 关键字标记的成员变量不参与序列化过程

private static final long serialVersionUID = -1589804003600796026L;


serialVersionUID 辅助序列化和反序列化过程,序列化后的数据的 serialVersionUID 要和 当前类的 serialVersionUID 相等才能被正常地反序列化

【关于 Parcelable 需要知道的几点】

方法 / 功能 / 标记位
createFromParcel(Parcel in) / 从序列化后的对象中创建原始对象 /
newArray(int size) / 创建指定长度的原始对象数组 /
User(Parcel in) / 从序列化后的对象中创建原始对象 /
writeToParcel(Parcel out, int flags) / 将当前对象写入序列化结构中,其中 flags 标识有两种值:0 或 1,为 1 时标识当前对象需要作为返回值返回,不能立即释放资源,几乎所有情况都为 0 / PARCELABLE_WRITE_RETURN_VALUE
describeContents / 返回当前对象的内容描述。如果含有文件描述符,返回 1,否则返回 0, 几乎所有情况都返回 0 / CONTENTS_FILE_DESCRIPTOR
[ 对 Parcelable 的典型用法示例 ]

public class User implements Parcelable{
public int userId;
public String userName;
public boolean isMale;
public Book book;

public User(int userId, String userName, boolean isMale){
this.userId = userId;
this.userName = userName;
this.isMale = isMale;
}

// 内容描述功能
public int describeContents(){
return 0;
}

// 序列化功能的完成,最终通过 Pacel 中的一系列 write 方法来完成
public void writeToParcel(Parcel out, int flags){
out.wirteInt(userId);
out.writeString(userName);
out.writeInt(isMale ? 1 : 0);
out.writeOarcelable(book, 0);
}

// 反序列化功能的完成
public static final Parcelable.Creator<User> CREATOR = new Parcelable.Creator<User>() {
public User createFromParcel(Parcel in) {
return new User(in);
}
public User[] newArray(int size){
return new User[size];
}
};

private User(Parcel in){
userId = in.readInt();
userName = in.readString();
isMale = in.readInt() == 1;
book = in.readParcelable(Thread.currentThread().getContextClass-Loader());
}
}


[ 对两种序列化接口的比较:]

Serializable / Parcelable
Serializable 是 Java 提供的序列化接口 / Parcelable 是 Android 提供的序列化接口,更适合在 Android 平台上
Serializable 使用简单但是开销大,序列化和反序列化过程中需要大量的 IO 操作 / Parcelable 使用麻烦但是效率很高
【Binder】

需要知道的几点 ↓

Binder 是 Android 的一个实现了 IBinder 接口的类。

是 Android 的一种跨进程通信方式

是一种虚拟的物理设备,设备驱动是 /dev/binder

从 Android Framework 角度来看,Binder 是 ServiceManager 连接各种 Manager(ActivityManager、WindowManager 等等)和相应的 ManagerService 的桥梁。

从 Android 应用层来说,是客户端和服务端进行通信的媒介

Binder 主要用在 Service 中,包括 AIDL、Messenger(底层也是 AIDL)

所有可以在 Binder 中传输的接口都需要继承 IInterface 接口

关于 Binder 的知识需要单独总结一下:读 Android 开发艺术探索 &3 (番外篇之弄懂 Binder)

End.

Note by HF.

Learn from 《Android 开发艺术探索》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android