网站开发的响应式和兼容性问题,中企动力销售好处单吗,网站开发建设价格附件,淘宝客网站做百度竞价概述
记得上篇文章我们留下的问题吗#xff1f;如果还没有看过上一篇讲解Handler基本原理文章的同学可以补一下知识。Android 线程间通信(一) - Handler
回到正题#xff0c;这次我们将一下上一篇文章留下问题中的几个#xff0c;idleHandler syncBarrier。
同步屏…概述
记得上篇文章我们留下的问题吗如果还没有看过上一篇讲解Handler基本原理文章的同学可以补一下知识。Android 线程间通信(一) - Handler
回到正题这次我们将一下上一篇文章留下问题中的几个idleHandler syncBarrier。
同步屏障
首先我们了解吗我们平时通过Handler#sendMessage发送的属于什么消息同步消息还是异步消息。既然这次讲到同步屏障我们也可以大胆的猜想我们平时发送的消息是同步消息只有特殊情况下插入这个同步屏障才会走特殊的异步方式。 如果能够这样推导说明在Handler这一块的了解已经比较深刻了。我们继续看一下源码。 //MessageQueue.javaUnsupportedAppUsageMessage next() {...int pendingIdleHandlerCount -1; // -1 only during first iterationint 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;//(1) msg不为空且msg.target为空才会进入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;}...}我们看代码中(1)注解的位置msg不为空这个很好理解消息需要有实体但是target为空这个是为什么呢上一片文章讲过msg的target其实就是Handler。而下面官方的注解说明被栏栅挡住了在队列中查找下一个异步消息。然后开始从当前这个msg的下一个msg开始查找知道下一个消息属于异步消息或者查找直到为空位置跳出循环。
可见挡住同步消息的正是这个msg.targetnull的消息那么它是怎么插入进来的呢我们接着看。 //MessageQueue.javaUnsupportedAppUsageTestApipublic int postSyncBarrier() {return postSyncBarrier(SystemClock.uptimeMillis());}private int postSyncBarrier(long when) {// Enqueue a new sync barrier token.// We dont 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;Message prev null;Message p mMessages;if (when ! 0) {while (p ! null p.when when) {prev p;p p.next;}}if (prev ! null) { // invariant: p prev.nextmsg.next p;prev.next msg;} else {msg.next p;mMessages msg;}return token;}}MessageQueue中有一个方法叫做postSyncBarrier可以理解为插入同步屏障。首先通过Message#obtain获取消息这里是对消息对象的一个复用在消息处理完之后会把Message的target清除。然后标记为使用接着就是消息的一些属性赋值但唯独没有重新确定msg的target对象。可见如果messageQueue需要插入同步屏障就是通过这个方法把屏障消息插入进去的。 插入同步屏障消息是直接通过MessageQueue进行插入 既然有插入同步屏障那么也有移除屏障让同步消息可以继续执行。 //MessageQueue.javaUnsupportedAppUsageTestApipublic 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);}}}还有个问题就是同步屏障是挡住同步消息那么怎么发送异步消息呢我们看看Message的源码。 // Message.javapublic void setAsynchronous(boolean async) {if (async) {flags | FLAG_ASYNCHRONOUS;} else {flags ~FLAG_ASYNCHRONOUS;}}有一个设置异步的方法根据传入的bool值flags和标志位做位运算。我们只要了解当async为trueflags 1async为falseflags 0。之前跳出next中的do…while循环中判断异步消息的方式就是msg#isAsynchironous。也就是说setAsynchronous当传入true的时候判断消息的条件就为真此时发送的消息就是异步消息了。 //Message.javapublic boolean isAsynchronous() {return (flags FLAG_ASYNCHRONOUS) ! 0;}默认情况下flags 0为同步消息 这样一来同步屏障的作用和使用方式我们就彻底搞懂了。
IdleHandler
空闲Handler和字面意思一样。Handler是消息处理的句柄那么IdleHandler就是处理空闲消息的句柄。在MessageQueue#next源码中我们继续看一下。 //MessageQueue#next// If first time idle, then get the number of idlers to run.// Idle handles only run if the queue is empty or if the first message// in the queue (possibly a barrier) is due to be handled in the future.if (pendingIdleHandlerCount 0 (mMessages null || now mMessages.when)) {pendingIdleHandlerCount mIdleHandlers.size();}if (pendingIdleHandlerCount 0) {// No idle handlers to run. Loop and wait some more.mBlocked true;continue;}if (mPendingIdleHandlers null) {mPendingIdleHandlers new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];}mPendingIdleHandlers mIdleHandlers.toArray(mPendingIdleHandlers);}// Run the idle handlers.// We only ever reach this code block during the first iteration.for (int i 0; i pendingIdleHandlerCount; i) {final IdleHandler idler mPendingIdleHandlers[i];mPendingIdleHandlers[i] null; // release the reference to the handlerboolean keep false;try {keep idler.queueIdle();} catch (Throwable t) {Log.wtf(TAG, IdleHandler threw exception, t);}if (!keep) {synchronized (this) {mIdleHandlers.remove(idler);}}}// Reset the idle handler count to 0 so we do not run them again.pendingIdleHandlerCount 0;// While calling an idle handler, a new message could have been delivered// so go back and look again for a pending message without waiting.nextPollTimeoutMillis 0;}next方法下面有这样一段代码什么时候会执行下去呢就是当msgnull的时候因为当msg不为空说明取出了msg并返回给Looper进行后续分发了。msg为null说明此时消息队列中取不出消息了就会从mIdlehandlers这个集合中获取集合大小并且把集合转换成数组mPendingIdleHandlers。
接着通过一个for循环取出每一个idler并执行它的queueIdle这个queueIdle是一个接口可见是一个接口回调的操作回调给用户去操作了。 //MessageQueue.javapublic void addIdleHandler(NonNull IdleHandler handler) {if (handler null) {throw new NullPointerException(Cant add a null IdleHandler);}synchronized (this) {mIdleHandlers.add(handler);}}通过MessageQueue的addIdleHandler接口我们可以向MessageQueue维护的集合中添加这种空闲Handler当消息队列MessageQueue的消息队列中没有任务可以执行之后就会执行这些空闲的消息。
可以发现IdleHandler适合处理那些优先级比较低的事情而不会影响到用户界面的响应性。避免在主线程繁忙的时候执行耗时任务从而保持应用的流畅性。
总结
1、MessageQueue可以发送同步屏障消息 2、Message可以通过设置确认发送的消息为同步还是异步 3、同步屏障消息的Handler为空 4、MessageQueue可以添加IdleHandler来处理优先级较低的任务
这下应用层Handler的东西我们都了解了。下一篇文章接下来将通过native层来分析一下Handler这个线程间通信的方式底层到底还做了什么。