转载请以链接形式标明出处: 本文出自:103style的博客
《Android开发艺术探索》 学习记录
进程间通信 即 IPC机制,IPC 全称为 Inter-Process Communication。
首先我们先了解下什么是进程,什么是线程?
PC的一个程序 或者 移动设备的一个应用.一个进程可以包含多个线程。
IPC 不是 Android 独有的,任何一个操作系统都需要相应的 IPC 机制。比如:
Android 是一种基于 Linux内核 的移动操作系统,它的进程间通信并不能完全继承 Linux,它有自己的进程间通信方式,比如:Binder、Socket.
这里我们主要介绍两个问题:
那就是在 AndroidMainfest 文件中给 四大组件(Activity、Service、Receiver、ContentProvider) 指定 android:process。
当然 我们也可以通过 JNI 在 native层 去 fork 一个进程。
示例:
<activity
android:name=".SecondActivity"
android:process=":second" />
<service
android:name=".TestService"
android:process="com.lxk.test.testService" />
<receiver
android:name=".TestReceiver"
android:process=":testService" />
<provider
android:name=".TestContentProvider"
android:authorities="lxk"
android:process=":testContentProvider" />:xxx写法 会在前面添加当前的应用包名, 并且该进程为当前应用的私有进程。
不用:xxx写法的 TestService 则属于全局进程,其他应用可以通过 shareUID 方式和它跑在一个进程中。
运行程序,我们可以通过以下 shell 命令来查看.com.lxk.test 为包名
adb shell ps | grep com.lxk.test《Android开发艺术探索》的作者是这样形容多进程的——“当应用开启了多进程以后,各种奇怪的现象都出现了”。
原因是 Android为每一个进程都分配了一个独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,这会导致一个类的对象会在每一个上都有一个副本。
所以运行在不同进程中的四大组件,只要它们之间通过内存来共享数据,都会共享失败。
一般来说,使用多进程会出现以下问题:
这里我们是对 Serializable接口、Parcelable接口、Binder 的介绍。
Serializable是 Java 提供的一个序列化接口,是一个空接口,为对象提供标准的序列化和反序列化操作。
使用示例:
public class User implements Serializable {
public static final long serialVersionUID = 4516876541857684L;
public int userId;
public String name;
public int age;
}我们只需要实现 Serializable 接口,其他的工作几乎都被系统自动完成了。
使用 ObjectOutputStream 和 ObjectInputStream 也可以轻松实现对象的序列化和反序列化。
String url = "cache.txt";
User user = new User(1,"lxk",25);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(url));
oos.writeObject(user);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(url));
User newUser = (User) ois.readObject();
ois.close();我们注意到示例中有个 serialVersionUID,它是用来做什么的呢?
serialVersionUID 一般是 IDE 根据当前类的结构自动生成的它的 hash值,它并不是必须的。
它的作用主要是用来 区分序列化的内容对应的类的结构是否发生了变化,如果结构发生了变化,就会导致序列化失败,程序crash.
当我们不需要序列化某些字段的时候,我们可以用 transient 字段来修饰.
public class User implements Serializable {
public static final long serialVersionUID = 4516876541857684L;
public int userId;
public String name;
public int age;
public transient int temp;
}Parcelable是 Android 提供的序列化方式。
Parcelable 也是一个接口,我们只要实现这个接口,然后根据AndroidStudio的提示重写对应方法。
public class User implements Parcelable {
public static final Creator<User> CREATOR = new Creator<User>() {
@Override
public User createFromParcel(Parcel in) {
return new User(in);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
public int userId;
public String name;
public int age;
protected User(Parcel in) {
userId = in.readInt();
name = in.readString();
age = in.readInt();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(userId);
dest.writeString(name);
dest.writeInt(age);
}
@Override
public int describeContents() {
return 0;
}
}这里先说下,Parcel 内部包装了可序列化的数据,可以在 Binder 中自由传输。
通过以上示例代码,我们知道 序列化是由 writeToParcel 及 Parcel 的一系列 write 方法完成的,反序列化是由 CREATOR 及 Parcel 的一系列 read 方法完成的.
Parcelable的方法说明:
方法 | 功能 | 标记位 |
|---|---|---|
createFromParcel(Parcel in) | 从序列化后的对象中创建原始对象. | |
newArray(int size) | 创建指定长度的原始数据对象数组. | |
User(Parcel in) | 从序列化后的对象中创建原始对象. | |
writeToParcel(Parcel dest, int flags) | 将当前对象写入序列化结构中. flags包含右侧标记为的值. 1 表示 正在写入的对象是一个返回值,一些实现可能在此时释放资源. 2 表示父对象将负责管理名义上跨其内部数据成员复制的重复状态/数据. 几乎所有情况都是 0. | PARCELABLE_WRITE_RETURN_VALUE = 0x0001 PARCELABLE_ELIDE_DUPLICATES = 0x0002 |
describeContents() | 返回当前对象的内容描述. 1 表示包括文件描述符. 几乎所有情况都是 0. | CONTENTS_FILE_DESCRIPTOR = 0x0001 |
系统为我们提供了许多实现了 Parcelable 接口的类,它们都是可以直接序列化的。比如: Intent、Bitmap、Bundle等,同时 List、Map也可以序列化。
Serializable 和 Parcelable对比
Serializable 是Java提供的序列化接口,使用起来简单但是开销大,需要大量的 I/O操作。
Parcelable 是 Android提供的序列化接口,适合在Android平台,缺点就是使用起来相对麻烦点,但是效率高。
内存序列化 选 Parcelable.
序列化到存储设备 或者 序列化之后进行网络传输 则选 Serializable.
AndroidMainfest 文件中给 四大组件指定 android:process即可指定不同的进程。Serializable 和 Parcelable 接口的使用和优缺点,内存序列化 选 Parcelable,否则选 Serializable。如果觉得不错的话,请帮忙点个赞呗。
以上