前言
2022年,我要稳扎稳打!扎实基础,才能厚积薄发!
关于序列化:parcelable 和serializable的区别?
- 使用上:parcelable和serializable都是接口
parcelable:序列化通过writeToParcel方法,反序列化通过创建creator类实现其中的createFromParcel(Parcel in)方法和newArray(int size)方法,前者是通过读取in流得到每个成员变量,后者是指定对象的数组长度,如果size大于1说明是个数组
serializable:序列化和反序列化通过ObjectOutputStream和ObjectInputStream字节流的操作,序列化通过writeObject方法,反序列化通过readObject方法,其中需要通过反射得到两个关键了类:ObjectStreamClass和ObjectStreamField,在ObjectStreamClass中通过反射那倒bean类的类名、是否重写了writeObject以及readObject方法(以及writeReplace和readReplace方法),因为每次序列化都需要用到反射,且没有缓存,因此效率上大大降低,相对parcelable来说要慢很多,有测试验证将近10倍. - 应用场景上:
parcelable 一般用在安卓进程间的通信,进程间数据传递基于binder,数据的复制基于memcpy,由于是native层的实现,直接操作的内存,因此速度很快,效率很高。
serializable一般用在I/O上的,通常我们序列化和反序列化都是用的ObjectOutputStream和ObjectInputStream,直接通过字节流对基础数据的I/O操作,通过Java层的实现,创建大量的对象,且用每次都用到反射,那么速度慢,且效率低
关于进程间的通信
linux IPC进程间的通信有哪些?
- 管道:管道是最古老的一种通信方式,半双工,也就是单通道,管道其实是一个内核缓存区,创建时会分配一个page大小的内存,大小有限,一端写入另一端读出,当写满或者读空的时候,通过等待和唤醒的方式进行通信;管道分为无名管道(pipe)和有名管道(FIFO)
pipe:只能用户父子进程间或兄弟进程间的通信,而且需要二次拷贝
FIFO:有名管道就是有一个名字,这个名是文件名,任何进程持有这个名字,在有访问权限的情况下,都可以对文件进行访问操作; - 信号(Sign):信号可以分为可靠信号和不可靠信号,也可以分为实时信号和非实时信号;信号的可靠性只与值有关,信号值小于SIGRTMIN的值都是不可靠的,SIGRTMIN和SIGRTMAX的值都是可靠的;
- 消息队列MessageQueue:消息队列是一个链表,相比信号它可以传递更多的信息,相比于管道,它克服了无格式字节流和缓冲区大小受限的缺点
- 共享内存SharedMemory:它是IPC通信中速度最快的一种,进程直接映射一块内存,可以同时被其他进程访问,实现零拷贝
- 套接字(socket):socket其实是一个套接字,是对TCP协议和UDP协议的封装可以用于进程间的传输,也可以用于网络间的传输
在Android中进程间的通信有哪些?
- binder通信(广播、AIDL,acticity之间的数据传递都是基于binder通信)。关于binder的实现原理,可以参考这边文章,很详细(Android Binder框架)binder通信的五大特点:
(1)性能上:管道、消息队列、socket都需要两次拷贝,共享内存了零拷贝,而binder只需要1拷贝,因此在性能仅次于共享内存
(2)稳定性:binder采用的是C/S架构,因此客户端和服务端相对独立,而共享内存没有这方面的区分,需要充分考虑临界资源的并发访问问题
(3)安全性:传统的Linux IPC的接受方法面向进程的,也就是通过进程提供的PID去识别对方的身份,PID容易被伪造不安全。而binder则是为每个来访的进做UID的校验,相对安全 - socket通信:例如zygote进程采用的就是socket通信机制,其他大部分的都是采用的binder通信机制
- 文件file传输:
- contentProvider:
- SQLite数据库:
关于Activity的启动模式launchMode
- launchMode分为4中:standard、singleTop、singleTask、singleInstance;
- standard:
当前栈:标准启动模式,每次启动,都会创建新的实例并压入到栈顶
非当前栈:如果activity标记了FLAG_ACTIVITY_NEW_TASK
(1)获取该activity的affinity得到aA;
(2)检查是否存在一个affinity为aA的任务,如果不存在,则创建新的task,并创建新的实例,如果存在,则直接创建实例 - singleTop:
当前栈:如果activity在任务的栈顶,则不会创建新的,直接调用onNewIntent()方法重新传递值,如果非栈顶,则和standard相同
非当前栈:如果activity标记了FLAG_ACTIVITY_NEW_TASK
(1)获取该activity的affinity得到aA;
(2)检查是否存在一个affinity为aA的任务,如果不存在,则创建新的task,并创建新的实例,如果存在,顶部是否是要创建的Activity,如果不是则创建,如果是,则不创建 - singleTask:
当前栈:如果activity不存在,则创建实例并压栈,如果存在则复用该activity并清除其顶部的所有类,同时调用onNewIntent()方法。
非当前栈:如果activity标记了FLAG_ACTIVITY_NEW_TASK
(1)获取该activity的affinity得到aA;
(2)检查是否存在一个affinity为aA的任务,如果不存在,则创建新的task,并创建新的实例,如果存在,复用该activity并清除其顶部的所有类,同时调用onNewIntent()方法。 - singleInstance:单例模式,而且是系统的全局单例,如果该activity被标记为singleInstance启动模式,那么不论从哪个应用去拉起该activity都是复用同一个类。
总结:类的启动模式其实是针对系统的,而不单是针对某个应用的,对应的是TaskRecord类去管理,而且启动模式只有activity才有,其他几个组件没有启动模式。