ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
### 三、IPC基础概念介绍 当我们需要通过Intent和Binder传输数据时就需要使用Parcelable或者Serializeble。Serializable和Parcelable接口可以完成对象的序列化过程。还有时候我们需要把对象持久化到存储 设备上或者通过网络传输给其他客户端,这个时候也需要Serializable来完成对象的持久化。 #### 1、Serializable接口 (1)Serializable是Java所提供的一个序列化接口,它是一个空接口,为对象提供标准的序列化和反序列化操作。使用Serializable来实现序列化非常简单,只需要在类的声明中指定一个类似下面的标识即可自动实现默认的序列化过程。 ~~~ private static final long serialVersionUID = 8723148825838841922L; public class User implements Serializable{ private static final long serialVersionUID = 8723148825838841922L; public int userId; public String userName; public boolean isMale; } ~~~ (2)只需要采用ObjectOutputStream和ObjectInputStream即可轻松实现对象的序列化和反序列化过程: ~~~ // 序列化过程: User user = new User(0,"jake",true); ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("cache.txt")); out.writeObject(user); out.close(); // 反序列化过程: ObjectInputStream in = new ObjectInputStream(new FileInputStream("cache.txt")); User newUser = (User)in.readObject(); in.close(); ~~~ **注意点一**:序列化和反序列化的对象并不是同一个对象! (3)一般来说,我们应该手动指定serialVersionUID的值,比如1L,也可以让Eclipse根据当前类的结构自动去生成它的hash值。当我们手动指定了它以后,就可以在很大程度上避免反序列化过程的失败。 **注意点二**:静态成员变量属于类不属于对象,所以不会参与序列化过程。 **注意点三**:用transient关键字标记的成员变量不参与序列化过程。 **注意点四**:通过重写writeObject和readObject方法可以改变系统默认的序列化过程。 #### 2、Parcelable接口 在Android 中也提供了新的序列化方式,那就是Parcelable 接口,使用Parcelable 来实现对象的序列号,其过程要稍微复杂一些。 (1)Parcelable也是一个接口,只要实现这个接口,一个类的对象就可以实现序列化并可以通过Intent和Binder传递。 ~~~ 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; } /* * 内容描述功能几乎都是直接返回0的。 * */ public int describeContents() { return 0; } /* * 序列化由writeToParcel方法来完成,最终是通过Parcel中一系列write方法来完成的。 * 其中flags标识有两种值:0和1(PARCELABLE_WRITE_RETURN_VALUE)。 * 为1时标识当前对象需要作为返回值返回,不能立即释放资源, * 几乎所有情况都为0。 * */ public void writeToParcel(Parcel out, int flags) { out.writeInt(userId); out.writeString(userName); out.writeInt(isMale? 1:0); out.writeParcelable(book, 0); } /* * 反序列化功能是由CREATOR来完成,其内部标明了如何创建序列化对象和数组, * 并通过Parcel的一些了read方法来完成反序列化过程。 * */ 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]; } }; /* * Parcel内部包装了可序列化的数据,可以在Binder中自由传输。 * 从序列化后的对象中创建原始对象。 * */ private User(Parcel in) { userId = in.readInt(); userName = in.readString(); isMale = in.readInt() == 1; /* * 由于book是另一个可序列化对象,所以它的反序列化过程需要传递当前线程的上下文类加载器, * 否则会报无法找到类的错误。 * */ book = in.readParcelable(Thread.currentThread().getContextClassLoader()); } } ~~~ Parcelable的方法说明如下表 ![](https://box.kancloud.cn/efb8efbcb6b87a3124c31445f34aec4d_1202x470.png) (2)系统已经为我们提供了许多实现了Parcelable接口的类,它们都是可以直接序列化的,比如Intent、Bundle、Bitmap等,同时List和Map也可以序列化,前提是它们里面的每个元素都是可序列化的。 ** Parcelable接口和Serializable接口的比较** (1)Serializable用起来简单,但开销很大,序列化和反序列化过程都需要大量的I/O操作。 (2)Parcelable是Android中的序列化方式,更适合在Android平台上使用,用起来比较麻烦,但效率很高,首选。主要用在内存序列化上。通过Parcelable 将对象序列化到存储设备中或者将对象序列化后通过网络传输也都是可以的,但是这个过程会稍显复杂,因此在这两种情况下建议大家使用Serializable。 #### 3、Binder 直观来说Binder是Android中的一个类,它继承Ibinder接口。从IPC角度来说,Binder是Android中的一种跨进程通信的方式,Binder还可以理解为一种虚拟的物理设备,它的设备驱动是/dev/binder,该通信方式在Linux中没有。 从Android Framework的角度来说,Binder是ServiceManager连接各种Manager(ActivityManager、WindowManager,等等)和相应ManagerService的桥梁。 从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当bindService的时候,服务端会返回一个包含了服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务。 Android开发中,Binder主要用在Service中,包括AIDL和Messenger,其中普通Service中的Binder不涉及进程间通信。Messenger的核心其实是AIDL。这里选用aidl来分析Binder的工作机制。