直播平臺原始碼,資訊的雙端同步處理

zhibo系統開發發表於2022-05-06

直播平臺原始碼,資訊的雙端同步處理

Handler元件中包含:Looper、Message、MessageQueue、Handler。

在Message中,有一個變數flag,用於標記這個Message正在被使用、此訊息是非同步訊息等,通過一個方法isAsynchronous()可以獲取當前Message是否為非同步訊息。同時,在Message中有一個變數target,是Handler型別的,表示最終由這個Handler進行處理。

平時我們傳送訊息時,這個target是不可以為null的。

//MessageQueue.java
boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) {
        throw new IllegalArgumentException("Message must have a target.");
    }
    if (msg.isInUse()) {
        throw new IllegalStateException(msg + " This message is already in use.");
    }
}

但是在傳送屏障訊息的時候,target是可以為空的,它本身僅僅是起遮蔽普通訊息的作用,所以不需要target。MessageQueue中提供了postSyncBarrier()方法用於插入屏障訊息。

//MessageQueue.java
/**
 * @hide
 */
public int postSyncBarrier() {
    return postSyncBarrier(SystemClock.uptimeMillis());
}
private int postSyncBarrier(long when) {
    synchronized (this) {
        //這個token在移除屏障時會使用到
        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.next
            msg.next = p;
            prev.next = msg;
        } else {
            msg.next = p;
            mMessages = msg;
        }
        return token;
    }
}


看起來比較簡單,可以獲取的資訊如下:


屏障訊息和普通訊息區別在於螢幕沒有target,普通訊息有target是因為它需要將訊息分發給對應的target,而螢幕不需要被分發,它就是用來擋住普通訊息來保證非同步訊息優先處理的

屏障和普通訊息一樣可以根據時間來插入到訊息佇列中的適當位置,並且只會擋住它後面的同步訊息的分發

postSyncBarrier會返回一個token,利用這個token可以撤銷屏障

postSyncBarrier是hide的,使用它得用反射

插入普通訊息會喚醒訊息對了,但插入屏障不會

現在屏障已經插入到訊息佇列中了,它是如何擋住普通訊息而只需要非同步訊息進行執行的呢?Looper是通過MessageQueue的next方法來獲取訊息的,來看看

//MessageQueue.java
Message next() {
    ...
    int pendingIdleHandlerCount = -1;
    int nextPollTimeoutMillis = 0;
    for (;;) {
        //如有訊息被插入到訊息佇列或者超時時間到,就被喚醒,否則會阻塞在這裡
        nativePollOnce(ptr, nextPollTimeoutMillis);
        synchronized (this) {
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            //遇到屏障  它的target是空的
            if (msg != null && msg.target == null) {
                //找出屏障後面的非同步訊息,
                do {
                    prevMsg = msg;
                    msg = msg.next;
                    //isAsynchronous()返回true才是非同步訊息
                } while (msg != null && !msg.isAsynchronous());
            }
            
            //如果找到了非同步訊息
            if (msg != null) {
                if (now < msg.when) {
                    //還沒到處理時間,再等一會兒
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    //到處理時間了,就從連結串列中移除,返回這個訊息
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    msg.markInUse();
                    return msg;
                }
            } else {
                //如果沒有非同步訊息就一直休眠,等待被喚醒
                nextPollTimeoutMillis = -1;
            }
            ...
        }
        ...
    }
}


以上就是直播平臺原始碼,資訊的雙端同步處理, 更多內容歡迎關注之後的文章


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69978258/viewspace-2892504/,如需轉載,請註明出處,否則將追究法律責任。

相關文章