Android IPC知识点记录(一、基础概念介绍)
此篇文章是在看完《Android开发艺术探索》后的个人笔记小结,摘录书中大量的语句以及例子,特此声明
先谈谈IPC的使用场景:多进程,多进程的情况分为两种:第一种情况是一个应用因为某些原因需要采用多进程模式实现,第二种情况是当前应用需要向其他应用获取数据。接下来我们就从IPC
是什么开始说起……
IPC(Ienter-Process Communication)
含义为进程间通信或者跨进程通信,是指两个进程间进行数据交换的过程(区分进程和线程的关系:包含与被包含)。当然,IPC不是Android中独有的,任何一个操作系统都需要有相应的IPC机制,对于Android来说,它是一种基于Linux内核的移动操作系统,它有自己的进程间通信方式。下面我们来学习多进程的相关知识。
多进程模式
正常情况下,在Android中多进程是指一个应用中存在多个进程的情况。开启方法:给四大组件(Activity、Service、Receiver、ContentProvider)在AndroidMenifest中指定android:process属性,非常规方法:通过JNI在native层去fork一个新的进程。(JNI是什么鬼,待google资料)。多进程命名方式分为两种:一种是进程名以“:”开头的进程,它的完整进程名是当前的进程名前面附加上当前的包名,第二种是完整的命名方式;两者的区别:进程名以“:”开头的进程名属于当前应用的私有进程,其他应用的组件不可以和它跑在同一个进程中,而另一种命名方式属于全局进程,其他应用通过SharedUID方式可以和它跑在同一个进程中。###Android会为每个应用分配一个唯一的UID,具有相同UID的应用才能共享数据,两个应用通过SharedUID跑在同一个进程中是有要求的,需要两个应用具有相同的SharedUID并且签名相同才可以。在这种情况下,它们可以互相访问对方的私有数据。(SharedUID番外篇:http://www.cnblogs.com/mythou/p/3258715.html)
多进程模式的运行机制
我们知道Android为每一个应用分配了一个独立的虚拟机,或者说为每个进程都分配了一个独立的虚拟机。而不同虚拟机在内存分配上有不同的地址空间,这就导致了在不同的虚拟机访问同一个类的对象会产生多份副本:所有运行在不同进程中的四大组件,只要它们之间需要通过内存来共享数据,都会共享失败,这也就是多进程带来的主要影响。一般来说,使用多进程会造成如下几方面的问题:
- 静态成员和单例模式会完全失效
- 线程同步机制完全失效
- SharedPreferences的可靠性下降
- Application会多次创建
总结:在多进程模式中,不同进程的组件会拥有独立的虚拟机,Application以及内存空间。
IPC的基础知识
对象的序列化:Android中存在两种序列化方式:第一种是Serializable接口,是Java所提供的一个序列化接口,第二种是Parcelable,是Android中的序列化方式。
Serializable接口
实现Serializable只需要这个类实现Serializable接口并声明一个serialVersionUID既可,这个值可以用当前类的hash值,也可以自行指定。private static final long serialVersionUID = xxxxxL
serialVersionUID的作用:用来辅助序列化和反序列化过程的,原则上序列化后的数据中的serialVersionUID只有和当前类的serialVersionUID相同才能够正常地被反序列化。
1 | //序列化过程 |
注意:恢复后的对象newUser和user的内容完全一样,但是两者并不是同一对象(内存不同)。
序列化注意事项:
- 静态成员变量属于类不属于对象,所以不会参与序列化过程
- 用transient关键字标记的成员变量不参与序列化过程
如果不手动填写serialVersionUID,序列化的时候系统会自动算出一个serialVersionUID写到文件中,然后恢复的时候会再次计算,如果两者的serialVersionUID一致,也就是类没有被修改,那么不会影响反序列化,但是,一旦修改了类,那么计算出来的hash就不同了,反序列化的时候就会报错。程序会crash;如果手动填写,就算修改了类,只要不是毁灭性的修改(例如修改类名),那么反序列化时会尽最大的限度去进行反序列化,最大限度还原对象,而不是直接crash。
Parcelable接口
什么都不说了,先上代码:
1 | public class Book implements Parcelable{ |
}
在序列化过程需要实现的功能有序列化、反序列化和内容描述,序列化功能由writeToParcel()来完成,最终是通过Parcel中的一系列write()方法完成。反序列化由CREATOR来完成;内容描述功能由describeContents()完成,几乎所有情况下这个方法都应该返回0(仅当当前对象中存在文件描述符中他才会返回1)。
How to choose?
Serializable是Java的序列化接口,其使用起来简单但是开销很大,序列化和反序列化过程需要大量I/O操作;而Parcelable是Android的序列化方式,效率高但是使用起来稍微麻烦点(这是Android推荐的序列化方式,因此我们要首选Parcelable)。