Android-Handler源碼解析-Message

Android-Handler源碼解析-Message

源碼版本:

  • Handler:SDK-31

導(dǎo)航:

成員變量

// 標(biāo)識(shí)Message
public int what;

// 存儲(chǔ)簡單數(shù)據(jù),如果存儲(chǔ)復(fù)雜的數(shù)據(jù)使用setData()方法。
public int arg1;
public int arg2;

// 發(fā)送給接收者的任意對(duì)象。
public Object obj;

// 回復(fù)給發(fā)送者,用于跨進(jìn)程雙向通信。發(fā)送message時(shí)給其replyTo賦值,接收到該message的進(jìn)程,可以通過message.replyTo向發(fā)送方進(jìn)程發(fā)送message,從而實(shí)現(xiàn)雙向通信。
public Messenger replyTo;

public static final int UID_NONE = -1;
// 可選字段,表示發(fā)送消息的uid。這只對(duì)Messenger發(fā)布(跨進(jìn)程發(fā)布)的消息有效;否則,它就是-1。
public int sendingUid = UID_NONE;
// 可選字段,指示導(dǎo)致該消息進(jìn)入隊(duì)列的uid。
public int workSourceUid = UID_NONE;

// 在用標(biāo)記
/*package*/ static final int FLAG_IN_USE = 1 << 0;
// 異步標(biāo)記
/*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;
// copy的清空標(biāo)記
/*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
// 標(biāo)記位
@UnsupportedAppUsage
/*package*/ int flags;

// 執(zhí)行時(shí)刻,時(shí)刻基于SystemClock.uptimeMillis。
@UnsupportedAppUsage
public long when;

// 存儲(chǔ)復(fù)雜的數(shù)據(jù)
/*package*/ Bundle data;

// 消息的目標(biāo)處理器Handler,即由此Handler處理此消息。
@UnsupportedAppUsage
/*package*/ Handler target;

// 表示要處理的任務(wù)Callback,由Runnable實(shí)現(xiàn),通過handler.post Runnable的時(shí)候,Runnable會(huì)被存放在Message中,分發(fā)的時(shí)候再進(jìn)行回調(diào)通知。
@UnsupportedAppUsage
/*package*/ Runnable callback;

// 下個(gè)消息,用于實(shí)現(xiàn)鏈表結(jié)構(gòu)。
@UnsupportedAppUsage
/*package*/ Message next;

// 消息池的同步鎖對(duì)象,用戶消息池的消息獲?。╫btain()方法)和消息回收(recycleUnchecked()方法)。
/** @hide */
public static final Object sPoolSync = new Object();
// 消息池鏈表的頭,用于操作(增刪改查)鏈表。
private static Message sPool;
// 消息池中消息的數(shù)量
private static int sPoolSize = 0;
// 消息池中消息的最大數(shù)量,為50個(gè)。
private static final int MAX_POOL_SIZE = 50;
// 是否檢查消息的回收(recycle()方法),默認(rèn)true,如果檢查并且有問題,則拋出異常。
private static boolean gCheckRecycle = true;

說明:

  1. Message為什么需要持有Handler,因?yàn)?code>Message需要知道是哪個(gè)Handler要處理它。
  2. Handler相關(guān)介紹,請(qǐng)看Android-Handler源碼解析-Handler。

創(chuàng)建Message

想要使用發(fā)送Message,首先要創(chuàng)建Message,所以我們接下來看下它是如何被創(chuàng)建的。

new Message()

public Message() {
}

直接創(chuàng)建一個(gè)Message對(duì)象,之后可以設(shè)置它的屬性,未使用復(fù)用,不推薦使用。

Message.obtain()

Message.obtain()

public static Message obtain() {
    // 使用同步保證線程安全,因?yàn)榇朔椒梢栽谌我饩€程調(diào)用。
    synchronized (sPoolSync) {
        if (sPool != null) {
            // 消息池頭不為空,說明隊(duì)列有內(nèi)容,從中獲取一條消息并返回。緩存的
            Message m = sPool; // 消息池的Head元素
            sPool = m.next; // 緩存池Head為下個(gè)元素(移除m)
            m.next = null; // 斷開鏈接
            m.flags = 0; // 清除在用標(biāo)記
            sPoolSize--; // 池?cái)?shù)量減1
            return m; // 返回此消息
        }
    }
    // 消息池頭為空,說明隊(duì)列沒有內(nèi)容,直接創(chuàng)建一條消息并返回。
    return new Message();
}

Message.obtain()靜態(tài)方法,內(nèi)部用了全局消息池,使用了復(fù)用,推薦使用。

說明:

  1. 消息池獲取消息,它會(huì)獲取隊(duì)列第一條消息,并將此消息此隊(duì)列移除。

Message.obtain(Message)

public static Message obtain(Message orig) {
    // 獲取消息
    Message m = obtain();
    // 將orig的值復(fù)制到新消息中
    m.what = orig.what;
    m.arg1 = orig.arg1;
    m.arg2 = orig.arg2;
    m.obj = orig.obj;
    m.replyTo = orig.replyTo;
    m.sendingUid = orig.sendingUid;
    m.workSourceUid = orig.workSourceUid;
    if (orig.data != null) {
        m.data = new Bundle(orig.data);
    }
    m.target = orig.target;
    m.callback = orig.callback;

    return m;
}

Message.obtain()相同,但將現(xiàn)有Message(包括其target)的值復(fù)制新的消息中。

Message.obtain(Handler)

public static Message obtain(Handler h) {
    Message m = obtain();
    m.target = h;

    return m;
}

Message.obtain()相同,但設(shè)置了target成員的值。

Message.obtain(Handler, Runnable)

public static Message obtain(Handler h, Runnable callback) {
    Message m = obtain();
    m.target = h;
    m.callback = callback;

    return m;
}

Message.obtain()相同,但設(shè)置了targetcallback成員的值。

Message.obtain(Handler, int)

public static Message obtain(Handler h, int what) {
    Message m = obtain();
    m.target = h;
    m.what = what;

    return m;
}Message.

Message.obtain()相同,但設(shè)置了targetwhat成員的值。

Message.obtain(Handler, int, Object)

public static Message obtain(Handler h, int what, Object obj) {
    Message m = obtain();
    m.target = h;
    m.what = what;
    m.obj = obj;

    return m;
}

Message.obtain()相同,但設(shè)置了target、whatobj成員的值。

Message.obtain(Handler, int, int, int)

public static Message obtain(Handler h, int what, int arg1, int arg2) {
    Message m = obtain();
    m.target = h;
    m.what = what;
    m.arg1 = arg1;
    m.arg2 = arg2;

    return m;
}

Message.obtain()相同,但設(shè)置了target、what、arg1arg2成員的值。

Message.obtain(Handler, int, int, int, Object)

public static Message obtain(Handler h, int what,
        int arg1, int arg2, Object obj) {
    Message m = obtain();
    m.target = h;
    m.what = what;
    m.arg1 = arg1;
    m.arg2 = arg2;
    m.obj = obj;

    return m;
}

Message.obtain()相同,但設(shè)置了target、what、arg1、arg2obj成員的值。

小結(jié)

  1. Message創(chuàng)建,有兩種方式:new MessageMessage.obtain(),Message.obtain()內(nèi)部使用了復(fù)用,推薦使用

回收Message

由于Message.obtain()方式創(chuàng)建內(nèi)部使用了復(fù)用,所以我們接下來看下它是如何被回收的。

recycle()

public void recycle() {
    // 判斷是否在使用中
    if (isInUse()) {
        // 在使用中,直接返回,不進(jìn)行回收。
        if (gCheckRecycle) {
            // gCheckRecycle為true,為檢查消息的回收,并且回收時(shí)正在使用(有問題),則拋出異常。
            throw new IllegalStateException("This message cannot be recycled because it "
                    + "is still in use.");
        }
        return;
    }
    // 不在使用中,進(jìn)行回收。
    recycleUnchecked();
}

recycle()方法,為檢查回收,如果此消息處于使用狀態(tài),則不進(jìn)行回收否則調(diào)用recycleUnchecked()直接進(jìn)行回收。

isInUse()方法的使用看后面-其它-InUse,我們接下來看下gCheckRecycle屬性,它在updateCheckRecycle()方法內(nèi)進(jìn)行更改。

public static void updateCheckRecycle(int targetSdkVersion) {
    if (targetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {
        // 小于SDK 21,為false。
        gCheckRecycle = false;
    }
}

updateCheckRecycle()方法,為更新gCheckRecyclegCheckRecycle默認(rèn)為true,updateCheckRecycle()方法在ActivityThreadhandleBindApplication()方法(綁定App)內(nèi)調(diào)用,即gCheckRecycletargetSdkVersion小于21false(不檢查),大于、等于21ture(檢查)。

recycleUnchecked()

void recycleUnchecked() {
    // 將此消息標(biāo)記為在用,并判斷是否添加到消息池中。
    // 清除所有屬性
    flags = FLAG_IN_USE;
    what = 0;
    arg1 = 0;
    arg2 = 0;
    obj = null;
    replyTo = null;
    sendingUid = UID_NONE;
    workSourceUid = UID_NONE;
    when = 0;
    target = null;
    callback = null;
    data = null;

    // 同步,保證線程安全。
    synchronized (sPoolSync) {
        if (sPoolSize < MAX_POOL_SIZE) {
            // 小于最大值,則進(jìn)行添加,把此Message添加到鏈表的頭部。
            next = sPool; // 此Message的next指向鏈表的Head
            sPool = this; // 鏈表的Head為此Message 
            sPoolSize++; // 消息池?cái)?shù)量加1
        }
    }
}

recycleUnchecked()方法,為不檢查回收,會(huì)清除消息的所有屬性,以完成釋放,并判斷如果消息池消息數(shù)量沒有到達(dá)最大數(shù)量,則進(jìn)行添加,以完成回收。

說明:

  1. 消息池添加消息,它會(huì)將此消息添加到隊(duì)列頭部,并將此消息作為新的頭

小結(jié)

  1. Message回收,有兩種方式:recycle()檢查回收、recycleUnchecked()不檢查回收
  2. recycle(),判斷了消息如果處于使用狀態(tài),則不進(jìn)行回收,否則調(diào)用recycleUnchecked()進(jìn)行回收。
  3. recycleUnchecked(),會(huì)清除消息的所有屬性,并判斷如果消息池?cái)?shù)量沒到消息池最大數(shù)量,則進(jìn)行添加(添加到消息池的鏈表頭部)。

跨進(jìn)程通訊

由于Message實(shí)現(xiàn)了Parcelable接口,所以Message可以跨進(jìn)程傳輸,所以我們接下來看下它的具體實(shí)現(xiàn)。

writeToParcel()

public void writeToParcel(Parcel dest, int flags) {
    if (callback != null) {
        // callback不能跨進(jìn)程傳輸,拋出異常。
        throw new RuntimeException(
            "Can't marshal callbacks across processes.");
    }
    dest.writeInt(what);
    dest.writeInt(arg1);
    dest.writeInt(arg2);
    if (obj != null) {
        // obj不為空,跨進(jìn)程傳輸任意對(duì)象,必須實(shí)現(xiàn)Parcelable接口,否則拋出異常。
        try {
            Parcelable p = (Parcelable)obj;
            dest.writeInt(1); // 傳入1,標(biāo)記有存入obj對(duì)象。
            dest.writeParcelable(p, flags); // 寫入obj對(duì)象
        } catch (ClassCastException e) {
            throw new RuntimeException(
                "Can't marshal non-Parcelable objects across processes.");
        }
    } else {
        dest.writeInt(0); // 傳入0,標(biāo)記沒有存入obj對(duì)象。
    }
    dest.writeLong(when);
    dest.writeBundle(data);
    Messenger.writeMessengerOrNullToParcel(replyTo, dest); // 使用Messenger進(jìn)行寫入
    dest.writeInt(sendingUid);
    dest.writeInt(workSourceUid);
}

readFromParcel()

private void readFromParcel(Parcel source) {
    what = source.readInt();
    arg1 = source.readInt();
    arg2 = source.readInt();
    if (source.readInt() != 0) {
        // 有存入obj對(duì)象,進(jìn)行讀取。
        obj = source.readParcelable(getClass().getClassLoader());
    }
    when = source.readLong();
    data = source.readBundle();
    replyTo = Messenger.readMessengerOrNullFromParcel(source); // 使用Messenger進(jìn)行讀取
    sendingUid = source.readInt();
    workSourceUid = source.readInt();
}

小結(jié)

  1. Message跨進(jìn)程通訊,callback不能有值,obj如有值必須實(shí)現(xiàn)Parcelable接口。

屬性set、get方法

Messagewhen、targetcallback、data屬性對(duì)外提供了set、get方法,我們接下來看下它們的實(shí)現(xiàn)。

when

public long getWhen() {
    return when;
}

target

public void setTarget(Handler target) {
    this.target = target;
}

public Handler getTarget() {
    return target;
}

callback

public Runnable getCallback() {
    return callback;
}

data

public Bundle getData() {
    if (data == null) {
        data = new Bundle();
    }
    return data;
}

public Bundle peekData() {
    return data;
}

public void setData(Bundle data) {
    this.data = data;
}

其它

copyFrom()

public void copyFrom(Message o) {
    this.flags = o.flags & ~FLAGS_TO_CLEAR_ON_COPY_FROM;
    this.what = o.what;
    this.arg1 = o.arg1;
    this.arg2 = o.arg2;
    this.obj = o.obj;
    this.replyTo = o.replyTo;
    this.sendingUid = o.sendingUid;
    this.workSourceUid = o.workSourceUid;

    if (o.data != null) {
        this.data = (Bundle) o.data.clone();
    } else {
        this.data = null;
    }
}

指定Message的屬性,復(fù)制當(dāng)前Message中。

sendToTarget()

public void sendToTarget() {
    target.sendMessage(this);
}

此消息發(fā)送給自己目標(biāo)Handler,如果未設(shè)置此字段,則拋出空指針異常。

asynchronous(異步)

public boolean isAsynchronous() {
    return (flags & FLAG_ASYNCHRONOUS) != 0;
}

isAsynchronous()方法,判斷消息是否是異步的,如果是,則返回true。

public void setAsynchronous(boolean async) {
    if (async) {
        flags |= FLAG_ASYNCHRONOUS;
    } else {
        flags &= ~FLAG_ASYNCHRONOUS;
    }
}

setAsynchronous()方法,設(shè)置消息是否是異步的,這意味著它不受Looper同步屏障的影響。

說明:

  1. 消息,分為同步消息異步消息默認(rèn)同步消息。
  2. 同步屏障,會(huì)屏障同步消息,確保只有異步消息執(zhí)行,詳細(xì)請(qǐng)看Android-Handler源碼解析-MessageQueue-同步屏障。
  3. 某些操作(比如視圖失效)可能會(huì)在Looper消息隊(duì)列中引入同步屏障,以阻止后續(xù)消息滿足某些條件之前被傳遞。在view invalidation的情況下,調(diào)用android.view.View.invalidate后發(fā)布的消息會(huì)被一個(gè)同步屏障掛起,直到下一幀準(zhǔn)備被繪制。同步屏障確保在恢復(fù)之前完全處理了無效請(qǐng)求。
  4. 異步消息免于同步屏障。它們通常表示中斷、輸入事件其它必須獨(dú)立處理的信號(hào),即使其它工作已經(jīng)暫停。
  5. 請(qǐng)注意,異步消息可能是按同步消息順序交付的,盡管它們之間總是按順序交付的。如果這些消息的相對(duì)順序很重要,那么它們可能一開始就不應(yīng)該是異步的,謹(jǐn)慎使用

InUse

/*package*/ boolean isInUse() {
    return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
}

isInUse()方法,判斷是否處于使用狀態(tài)。

/*package*/ void markInUse() {
    flags |= FLAG_IN_USE;
}

markInUse()方法,標(biāo)記處于使用狀態(tài)。

總結(jié)

以上就是Handler源碼的Message源碼部分,Handler其它源碼部分看下面導(dǎo)航。之后會(huì)出其它Android源碼系列,請(qǐng)及時(shí)關(guān)注。如果你有什么問題,大家評(píng)論區(qū)見!

導(dǎo)航:

最后推薦一下我的網(wǎng)站,開發(fā)者的技術(shù)博客: devbolg.cn ,目前包含android相關(guān)的技術(shù),之后會(huì)面向全部開發(fā)者,歡迎大家來體驗(yàn)!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容