一、 Parcelable 和 Serializable 区别
- Parcelable是Android的接口,Serializable是java接口,都用于实现对象的序列化和反序列化
- Serializable的序列化和反序列化过程需要I/O操作,将对象转换为二进制流,方便在网络、内存中传输和将对象持久化到本地, Serializable的反序列化过程需要通过反射的模式创建对象,会产生大量的临时变量,如果需要序列化的对象很多的话有可能会频繁的触发GC导致系统触发stop the word, 从而导致系统卡顿。频繁的I/O操作也会影响性能。
-
Parcelable是基于内存实现的序列化和反序列化,写入过程会按照顺序写入内存,读取的时候需要把指针复位然后根据指针size按照顺序读取,所以要求写入顺序和读取顺序一致,因为没有I/O操作所以会更快。同时Parcelable也支持将序列化之后的数据存入到磁盘,但是也需要I/O;
二 、Android 冷启动流程
截屏2021-09-20 下午8.34.58.png
- Launcher 启动Activity
- 获取AMS代理对象启动Activity
- 构建ActivityStarter 执行execute
- 构建ActivityStack
- 判断如果进程不存在则重新创建通知AMS创建进程
- 进程为空创建进程执行ActivityThread main()
- 创建主线程Looper,并调用attach方法给AMS绑定客户端回调,用来控制Activity的整个启动流程
- ApplicationThread 回调handleCreateActivity,创建Activity对象,并执行attach方法,同时创建Window、WindowManager,并且将两者绑定
- setContentView 构建DectorView 和 parentContent, 并且将LayoutId解析完成后添加到parentContent
- ApplicationThread 回调handleResumeActivity,调用WindowManager addView(),添加DectorView
- GlobalWindowManager 调用addView(),添加DectorView
- 创建ViewRootImpl对象,并且调用setView(),添加DectorView,
- 执行ViewRootImpl#requestLayout, 向主线程MessageQueue发送同步屏障,并且发送消息
- 执行WindowManagerService.addToDisplayUser(),将ViewRootImpl的aidl接口和WindowManagerService绑定
- 垂直同步信号回调之后执行DectorView的绘制动作,执行measure layout draw 方法
总结:ViewRoomImpl 是系统服务和所有子view的桥接
三、同步屏障
- 如何添加同步屏障到MessageQueue
private int postSyncBarrier(long when) {
// Enqueue a new sync barrier token.
// We don't need to wake the queue because the purpose of a barrier is to stall it.
synchronized (this) {
final int token = mNextBarrierToken++;
final Message msg = Message.obtain();
msg.markInUse();
msg.when = when;
msg.arg1 = token;
//注意这里,同步屏障消息的msg的target字段为空
Message prev = null;
//p为对头
Message p = mMessages;
if (when != 0) {
//找到同步屏障消息的when的合适插入节点
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
}
//插入同步屏障消息
if (prev != null) { // invariant: p == prev.next
msg.next = p;
prev.next = msg;
} else {
msg.next = p;
mMessages = msg;
}
return token;
}
}
按照这样的插入方法,当前的同步屏障消息只能过滤后面消息,在看一下MesssageQueue的next()方法。
- 同步屏障如何过滤同步消息
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//还未到下一个任务的执行时间,线程休眠
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
//判断消息是否是同步屏障消息,如果是的话,找到下一个*异步*消息
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
//执行将消息从队列里取出来的动作,前驱指针和后继指针相互配合将消息从队列里取出来
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
//.....
}
- 如何删除同步屏障删除的
public void removeSyncBarrier(int token) {
// Remove a sync barrier token from the queue.
// If the queue is no longer stalled by a barrier then wake it.
synchronized (this) {
Message prev = null;
Message p = mMessages;
//找同步屏障节点
while (p != null && (p.target != null || p.arg1 != token)) {
prev = p;
p = p.next;
}
if (p == null) {
throw new IllegalStateException("The specified message queue synchronization "
+ " barrier token has not been posted or has already been removed.");
}
final boolean needWake;
if (prev != null) {
//找到了删除节点
prev.next = p.next;
needWake = false;
} else {
//一个都没找到
mMessages = p.next;
needWake = mMessages == null || mMessages.target != null;
}
p.recycleUnchecked();
// If the loop is quitting then it is already awake.
// We can assume mPtr != 0 when mQuitting is false.
if (needWake && !mQuitting) {
//唤醒线程,将队列激活
nativeWake(mPtr);
}
}
}
- 总结,同步屏障的作用是为了更优先的执行MessageQueue里的异步消息,比如ViewRootImpl里在绘制之前发出的同步屏障消息
四、 Choreographer
- Choreographer用户申请VSync(垂直同步信号),并在下一个Sync到来的时候回调,然后执行队列里的输入、动画等绘制逻辑。
- Choreographer是线程单例的和Looper一样。
- Choreographer中的关键对象有FrameDisplayEventReceiver(用来申请VSync, 回调VSync信号处理队列中的任务),FrameHandler(用来像当前线程发送消息),CallbackQueue(大小为4数组,每个数组的元素是单链表的头结点,用来记录不同类型的任务)
- 如果当前线程的MessageQueue在同步屏障之前还有同步任务在执行,并且执行时间比较长,这样的话就会影响后面的异步任务执行,这个时候如果超出了30真的阈值,则会Log提示。









网友评论