溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java?Handler同步屏障怎么實(shí)現(xiàn)

發(fā)布時(shí)間:2023-05-04 11:17:14 來源:億速云 閱讀:79 作者:iii 欄目:編程語言

本篇內(nèi)容主要講解“Java Handler同步屏障怎么實(shí)現(xiàn)”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Java Handler同步屏障怎么實(shí)現(xiàn)”吧!

1.在View的加載和繪制流程中,有一個(gè)編舞者類,mChoreographer。

mTraversalBarrier = mHandler.getLooper().postSyncBarrier();向MessageQueue中插入一條同步屏障消息,msg.target==null的消息,返回值mTraversalBarrier是一個(gè)int 的token值。

  void scheduleTraversals() {
    if (!mTraversalScheduled) {
      mTraversalScheduled = true;
       //向消息隊(duì)列插入一個(gè)同步屏障的消息。msg.target==null的消息
             mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
             mChoreographer.postCallback(
                  Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
    }
  }

mChoreographer.postCallback()方法會(huì)執(zhí)行mTraversalRunnable中的代碼。

mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);這個(gè)會(huì)根據(jù)上面產(chǎn)生的token值移出MessageQueue中的同步屏障消息。

 final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
 final class TraversalRunnable implements Runnable {
            @Override
            public void run() {
                doTraversal();
            }
  }
   void doTraversal() {
      if (mTraversalScheduled) {
          mTraversalScheduled = false;
          //移除同步屏障消息
          mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
          //在這個(gè)方法中會(huì)調(diào)用 measure layout draw,view的繪制繪制流程的方法
          performTraversals();
      }
    }

還是看這行代碼mHandler.getLooper().postSyncBarrier(),系統(tǒng)是怎么處理的。

獲取了一個(gè)沒有設(shè)置handler的Message。

int enqueueSyncBarrier(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++;
            // 這個(gè)msg.target沒有被賦值
            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.next
                msg.next = p;
                prev.next = msg;
            } else {
                msg.next = p;
                mMessages = msg;
            }
            return token;
        }
    }

正常我們通過handler發(fā)送消息,handler是不允許為空的。

 boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
   ...........
}

那系統(tǒng)為啥要發(fā)送一個(gè)handler為空的消息呢?

先看mChoreographer發(fā)了同步屏障消息后,又做了什么?

又發(fā)送了一個(gè)異步消息:msg.setAsynchronous(true),這個(gè)消息的handler不為null。

private void postCallbackDelayedInternal(int callbackType,
            Object action, Object token, long delayMillis) {
      synchronized (mLock) {
            final long now = SystemClock.uptimeMillis();
            final long dueTime = now + delayMillis;
            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
            if (dueTime <= now) {
                scheduleFrameLocked(now);
            } else {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
                msg.arg1 = callbackType;
                //將消息設(shè)置為異步消息
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, dueTime);
            }
        }
}

接下來看看MessageQueue是怎么去消息的,是如何對這個(gè)同步屏障消息怎么處理的。

 Message next() {
            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                //如果msg.target==null說明我們已經(jīng)向消息隊(duì)里中插入了一條屏障消息。
                //此時(shí)會(huì)進(jìn)入到這個(gè)循環(huán)中,找到msg.isAsynchronous==true的異步消息。
                //通常我們發(fā)送的都是同步消息isAsynchronous = false的,并且msg.target不能為null的。
                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());//msg.isAsynchronous==true時(shí)結(jié)束循環(huán),說明找到了這個(gè)異步消息。
                }
                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 (false) Log.v("MessageQueue", "Returning message: " + msg);
                        return msg;
                    }
                } else {//沒有找到的話則進(jìn)入休眠直到下一次被喚醒
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }
        }
    }

在取消的時(shí)候,先判斷進(jìn)行msg.target為null的判斷,然后經(jīng)過while循環(huán),找到msg.isAsynchronous() == true的消息。也就是上面發(fā)送的異步消息。通常我們發(fā)送的消息都是同步消息,不會(huì)對對 msg.setAsynchronous(true);進(jìn)行設(shè)置。

系統(tǒng)這樣做的目的就是為了優(yōu)先去處理這個(gè)異步消息。會(huì)把所有的同步消息放在后面,向一道屏障一樣,所以這樣的操作,被稱為同步屏障,是同步屏障消息的處理有更高的優(yōu)先級(jí)。

因?yàn)榫幬枵哳恗Choreographer 負(fù)責(zé)屏幕的渲染,需要及時(shí)的處理從底層過來的信號(hào),以保障界面刷新的頻率。

到此,相信大家對“Java Handler同步屏障怎么實(shí)現(xiàn)”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI