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;
說明:
Message為什么需要持有Handler,因?yàn)?code>Message需要知道是哪個(gè)Handler要處理它。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ù)用,推薦使用。
說明:
- 從消息池中獲取消息,它會(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è)置了target和callback成員的值。
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è)置了target和what成員的值。
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、what和obj成員的值。
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、arg1和arg2成員的值。
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、arg2和obj成員的值。
小結(jié)
Message的創(chuàng)建,有兩種方式:new Message、Message.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()方法,為更新gCheckRecycle的值。gCheckRecycle默認(rèn)為true,updateCheckRecycle()方法在ActivityThread的handleBindApplication()方法(綁定App)內(nèi)調(diào)用,即gCheckRecycle在targetSdkVersion小于21為false(不檢查),大于、等于21為ture(檢查)。
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)行添加,以完成回收。
說明:
- 從消息池中添加消息,它會(huì)將此消息添加到隊(duì)列的頭部,并將此消息作為新的頭。
小結(jié)
Message的回收,有兩種方式:recycle()檢查回收、recycleUnchecked()不檢查回收。recycle(),判斷了消息如果處于使用狀態(tài),則不進(jìn)行回收,否則調(diào)用recycleUnchecked()進(jìn)行回收。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é)
Message的跨進(jìn)程通訊,callback不能有值,obj如有值則必須實(shí)現(xiàn)Parcelable接口。
屬性set、get方法
Message的when、target、callback、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同步屏障的影響。
說明:
- 消息,分為同步消息和異步消息,默認(rèn)為同步消息。
- 同步屏障,會(huì)屏障同步消息,確保只有異步消息執(zhí)行,詳細(xì)請(qǐng)看Android-Handler源碼解析-MessageQueue-同步屏障。
- 某些操作(比如視圖失效)可能會(huì)在
Looper的消息隊(duì)列中引入同步屏障,以阻止后續(xù)消息在滿足某些條件之前被傳遞。在view invalidation的情況下,調(diào)用android.view.View.invalidate后發(fā)布的消息會(huì)被一個(gè)同步屏障掛起,直到下一幀準(zhǔn)備被繪制。同步屏障確保在恢復(fù)之前完全處理了無效請(qǐng)求。- 異步消息免于同步屏障。它們通常表示中斷、輸入事件和其它必須獨(dú)立處理的信號(hào),即使其它工作已經(jīng)暫停。
- 請(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)!