Android提供的 Handler 消息收發(fā)處理機(jī)制,其根本目的就是解決多線程并發(fā)的問題,與之關(guān)聯(lián)的 Looper,Message,MessageQueue,無論是日常開發(fā)或者面試都是出場(chǎng)率極高,所以無論如何都必須搞清楚
Handler
導(dǎo)包要注意啦,package android.os
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
這是我們通常創(chuàng)建一個(gè) Handler 的方法,Handler 內(nèi)部創(chuàng)建調(diào)用實(shí)現(xiàn):
public Handler() {
this(null, false);
}
再跟進(jìn) Handler(Callback callback, boolean async) 方法實(shí)現(xiàn):
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
-
FIND_POTENTIAL_LEAKS是Handler中設(shè)置的一個(gè)標(biāo)志,如果將這個(gè)值設(shè)置為true用于檢測(cè)擴(kuò)展繼承Handler類是否存在潛在的內(nèi)存泄漏 -
Looper.myLooper()由于是默認(rèn)創(chuàng)建的handler,所以會(huì)自動(dòng)綁定主線程的Looper,并將主線程Looper維護(hù)的消息隊(duì)列(mLooper.mQueue)作為自己(Handler)的消息走向(往消息隊(duì)發(fā)送消息) -
callback用于是否攔截發(fā)送的消息(后面會(huì)解釋) -
mAsynchronous的作用是設(shè)置消息是否異步,這意味著發(fā)送的消息將不受Looper同步設(shè)置的影響
至此,通過 new Handler() 方法創(chuàng)建handler就完成了(關(guān)于Looper,后面會(huì)詳解)
創(chuàng)建
Handler實(shí)例 → 綁定主線程的Looper(只是默認(rèn)綁定主線程,也可以調(diào)用其他構(gòu)造方法指定Looper) → 連接綁定Looper所維護(hù)的MessageQueue→ 設(shè)置消息攔截回調(diào)和消息是否異步
那Handler怎么發(fā)送消息?
通常情況,我們會(huì)使用 handler.sendMessage() 來發(fā)送消息,如下:
Message message = handler.obtainMessage();
message.agr1 = 1;
.... //message信息攜帶操作
handler.sendMessage(message);
這樣消息就發(fā)送出去了,只要重寫了handler的 handleMessage(Message message) 便可以接收到消息進(jìn)行自己的邏輯處理。接下來看一下細(xì)節(jié)實(shí)現(xiàn):
-
handler.obtainMessage()會(huì)返回一個(gè)Message對(duì)象
public final Message obtainMessage()
{
return Message.obtain(this);
}
繼續(xù)跟進(jìn)Message的 obtain(this) 方法
public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;
return m;
}
obtain() 方法,從全局池中返回一個(gè)新的 Message 對(duì)象實(shí)例,可以在很多情況下避免分配新的對(duì)象。并給這個(gè)消息對(duì)象設(shè)置了 target 屬性,指定這個(gè)消息由誰(shuí)發(fā)送并由誰(shuí)處理。下面是 obtain() 方法:
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
這樣,我們就拿了一個(gè)指定了消息發(fā)送和處理者的 Message,它的消息攜帶后面再說。當(dāng)然,也可以不用 obtainMessage() 方法來獲取消息對(duì)象,完全可以自己 new Message() 對(duì)象來攜帶信息并發(fā)送,但是 obtain() 方法的注釋也說明了,有更好的方法為什么不用吶
-
sendMessage(Message msg)發(fā)送消息
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
調(diào)用了 sendMessageDelayed(msg, 0) 方法
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
//處理了時(shí)間不正確的情況,自己寫代碼的時(shí)候也應(yīng)該要考慮完善各種情況
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
//默認(rèn)構(gòu)造方法中設(shè)置了關(guān)聯(lián)主線程Looper的消息隊(duì)列,所以如果消息隊(duì)列為空則拋出異常
if (queue == null) {
RuntimeException e = new RuntimeException(this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//再次確認(rèn)消息的發(fā)送和處理者,所以即便自己 new Message() 忘了設(shè)置target也不用擔(dān)心
msg.target = this;
//這里用到了默認(rèn)構(gòu)造方法中設(shè)置的 async 屬性,設(shè)置消息是否異步
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
queue.enqueueMessage(msg, uptimeMillis) 方法有點(diǎn)復(fù)雜,這里就不貼了,它做的事情就是根據(jù) msg 和 uptimeMillis 與消息隊(duì)列里現(xiàn)有的消息比較,決定消息插入隊(duì)列的位置
當(dāng)然,也可以直接調(diào)用 sendMessageDelayed(Message msg, long delayMillis) 來延時(shí)發(fā)送消息
OK,現(xiàn)在消息已經(jīng)發(fā)送到消息隊(duì)列里面了,先處理完一些遺漏的地方,并先來看看 Handler是怎么在 handleMessage(Message msg) 方法中處理的,后面再說它怎么拿到消息 (劇透:Looper的死循環(huán))。
Handler的其他構(gòu)造方法
Handler 有很多構(gòu)造方法,在創(chuàng)建 Handler 的時(shí)候也可以使用 new Handler(Callback callback) 來創(chuàng)建。由上面的分析可見,new Handler() 默認(rèn)創(chuàng)建的時(shí)候,調(diào)用了this(null, false) 方法,默認(rèn)創(chuàng)建一個(gè)空的 callback ,那 callback 到底有什么作用?
首先得知道,Callback 是 Handler 內(nèi)部的一個(gè)接口,它包含一個(gè)返回 boolean 值的 handleMessage(Message msg) 方法,區(qū)別于 Handler 的 handleMessage(Message msg)(這個(gè)是不帶返回值的)
public interface Callback {
public boolean handleMessage(Message msg);
}
來創(chuàng)建一個(gè)帶 Callback 的 handler
Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
return false;
}
}){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
調(diào)用的是 Handler(Callback callback) 方法來創(chuàng)建,傳入了一個(gè) callback 并重寫 handlerMessage(Message msg)
public Handler(Callback callback) {
this(callback, false);
}
還是調(diào)用的 Handler(Callback callback, boolean async) 方法來創(chuàng)建 Handler,不清楚看上面的分析。
好了,到了 callback 的作用了,這個(gè)方法其實(shí)就是在處理消息的時(shí)候用到的,先來看一下 Handler 的 handleMessage(Message msg) 方法(),它負(fù)責(zé)處理接收到的消息,也是我們經(jīng)常需要重寫的方法,那 Handler 的 handleMessage(Message msg) 是怎么被觸發(fā)的,答案就在 Looper 的死循環(huán)中 --> msg.target.dispatchMessage(msg)(后面詳解)
Message 的 target 上面已經(jīng)說明了,它指定了消息發(fā)送和處理的 Handler, msg.target.dispatchMessage(msg) 這句話就是觸發(fā) Handler 進(jìn)行消息處理,先上源碼
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
//首先檢查msg是否設(shè)置了回調(diào)
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
//重點(diǎn)在這里,callback的handleMessage()方法的返回值決定了是否攔截消息
//重點(diǎn)在這里,callback的handleMessage()方法的返回值決定了是否攔截消息
//重點(diǎn)在這里,callback的handleMessage()方法的返回值決定了是否攔截消息
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
重要的事情說三遍,攔截以后的消息,不會(huì)調(diào)用 Handler 的 handleMessage(Message msg)方法,所以如果你需要對(duì)某些特定消息進(jìn)行攔截,可以給一個(gè) callback,并根據(jù)消息攜帶的信息來決定是否攔截
Handler的其他用法
-
Handler不僅能發(fā)送Message對(duì)象,還能post(Runnable runnable)到消息隊(duì)列中
/**
* Causes the Runnable r to be added to the message queue
* The runnable will be run on the thread to which this handler is
* attached.
*
* @param r The Runnable that will be executed.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
注釋清晰明了
可能上面 dispatchMessage() 的時(shí)候還會(huì)有疑惑,為什么 Message 也有 Callback?為什么 Runnable 能直接扔到消息隊(duì)列中? 。現(xiàn)在算是明白了。盡管 post() 出去的是一個(gè) Runnable 但 Handler 自己幫我們把它封裝成了 Message
Handler post Runnable后是直接把run()中的代碼送回到了Handler附屬的線程,通常就是創(chuàng)建Handler的主線程,所以我們經(jīng)常使用handler.post()在子線程中更新UI
當(dāng)然,也可以使用 postDelayed(Runnable r, long delayMillis) 來延時(shí)發(fā)送,其實(shí)它最終還是調(diào)用的 sendMessageDelayed(getPostMessage(r), delayMillis)
-
Handler發(fā)送 空的Message對(duì)象
/**
* Sends a Message containing only the what value.
*/
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
最終也會(huì)調(diào)用我們熟悉的方法
空消息只會(huì)附帶一個(gè)
int類型的what值,可以用來進(jìn)行一些特殊類型或者攔截消息的判斷
(Message消息攜帶后面詳解)
//////////////////////////////////////// 華麗的分割線 ////////////////////////////////////////
//////////////////////////////////////// 華麗的分割線 ////////////////////////////////////////
//////////////////////////////////////// 華麗的分割線 ////////////////////////////////////////
Looper
對(duì) Looper 的理解現(xiàn)在還不是很到位,知道多少先記錄多少
開始之前要扯一點(diǎn)其他的東西,做Android開發(fā)也這么久了,一直都知道Android是基于JAVA的 (當(dāng)然現(xiàn)在Kotlin才是親兒子了),也知道每個(gè)JAVA程序都是有一個(gè)主入口 main()的,之前卻一直不知道Android程序的主入口在哪里,就只知道通過 AndroidMamifest.xml 配置好了 intent-filter 就可以啟動(dòng) activity,很尷尬......
那Android的主入口到底在哪里?首先得知道 ActivityThread,好吧,其實(shí)我也不知道,附上傳送門
Android ActivityThread(主線程或UI線程)簡(jiǎn)介
ActivityThread它管理應(yīng)用進(jìn)程的主線程的執(zhí)行(相當(dāng)于普通Java程序的main入口函數(shù)),并根據(jù)AMS的要求(通過IApplicationThread接口,AMS為Client、ActivityThread.ApplicationThread和Server)負(fù)責(zé)調(diào)度和執(zhí)行activities、broadcasts和其它操作。
主線程既要處理Activity組件的UI事件,又要處理Service后臺(tái)服務(wù)工作,通常會(huì)忙不過來。為了解決此問題,主線程可以創(chuàng)建多個(gè)子線程來處理后臺(tái)服務(wù)工作,而本身專心處理UI畫面的事件。
【主線程】的主要責(zé)任:
? 快速處理UI事件。而且只有它才處理UI事件, 其它線程還不能存取UI畫面上的對(duì)象(如TextView等),此時(shí), 主線程就叫做UI線程?;旧?,Android希望UI線程能根據(jù)用戶的要求做出快速響應(yīng),如果UI線程花太多時(shí)間處理后臺(tái)的工作,當(dāng)UI事件發(fā)生時(shí),讓用戶等待時(shí)間超過5秒而未處理,Android系統(tǒng)就會(huì)給用戶顯示ANR提示信息。只有UI線程才能執(zhí)行View派生類的onDraw()函數(shù)。
? 快速處理Broadcast消息。【主線程】除了處理UI事件之外,還要處理Broadcast消息。所以在BroadcastReceiver的onReceive()函數(shù)中,不宜占用太長(zhǎng)的時(shí)間,否則導(dǎo)致【主線程】無法處理其它的Broadcast消息或UI事件。如果占用時(shí)間超過10秒, Android系統(tǒng)就會(huì)給用戶顯示ANR提示信息。
注意事項(xiàng):
? 盡量避免讓【主線程】執(zhí)行耗時(shí)的操作,讓它能快速處理UI事件和Broadcast消息。
? BroadcastReceiver的子類都是無狀態(tài)的,即每次啟動(dòng)時(shí),才會(huì)創(chuàng)建其對(duì)象,然后調(diào)用它的onReceive()函數(shù),當(dāng)執(zhí)行完onReceive()函數(shù)時(shí),就立即刪除此對(duì)象。由于每次調(diào)用其函數(shù)時(shí),會(huì)重新創(chuàng)建一個(gè)新的對(duì)象,所以對(duì)象里的屬性值,是無法讓各函數(shù)所共享。
跑得有點(diǎn)遠(yuǎn),但是這些都是我們應(yīng)該知道或者熟悉的。之前又一次面試,被問到Framewark與應(yīng)用層怎么通訊?當(dāng)時(shí)一臉懵逼,看了傳送門那篇文章,現(xiàn)在還能說個(gè)大概,C/S方式,AMS,Binder等等。下面進(jìn)入正題,知道了Android管理應(yīng)用進(jìn)程的入口在 ActivityThread 中,那我們進(jìn)去看一下(ActivityThread 的 main() 方法)
public static void main(String[] args) {
...... //自動(dòng)屏蔽其他不需要或者看不懂的代碼
Looper.prepareMainLooper();
......
Looper.loop();
......
}
好像發(fā)現(xiàn)了什么的感覺,Looper 出現(xiàn)了,初始化了一個(gè)主線程的 Looper,然后執(zhí)行了它的 loop() 方法。我們可以這樣認(rèn)為,每個(gè)Android程序(進(jìn)程)啟動(dòng)的時(shí)候,會(huì)自動(dòng)創(chuàng)建一個(gè) Looper 對(duì)象,并開啟循環(huán)(調(diào)用 loop() 方法)拉取 MessageQueue (Looper 對(duì)象中維護(hù)的消息隊(duì)列)的消息??赡鼙硎霾皇呛軠?zhǔn)確,但是可以這樣的理解。接著跟進(jìn)里面的方法:
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
注意最后一句注釋:應(yīng)用的主 Looper會(huì)由Android系統(tǒng)自動(dòng)創(chuàng)建,因此我們不需要手動(dòng)調(diào)用這個(gè)方法?,F(xiàn)在好像也不明白這個(gè)方法干了什么,準(zhǔn)備了什么,開啟了一個(gè)同步鎖保證線程安全,最后把 myLooper() 返回值賦給了 sMainLooper,繼續(xù)跟進(jìn) prepare()
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
這里看到了 new Looper(quitAllowed) 明白是創(chuàng)建了一個(gè) Looper,再結(jié)合 myLooper() 一起解釋:
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
到了這里,我們需要搞清楚 sThreadLocal 、sMainLooper 等屬性到底是什么,先來看一下 Looper 類中最開始定義的幾個(gè)變量:
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
-
sThreadLocal屬性,ThreadLocal這個(gè)東西應(yīng)該翻譯為:線程局部變量,不是線程?。?!,它干了什么事?(變量是同一個(gè),但是每個(gè)線程都使用同一個(gè)初始值,也就是使用同一個(gè)變量的一個(gè)新的副本。)保證了Looper的線程安全,并保證每個(gè)線程使用的是同一個(gè)Looper的不同副本。(有點(diǎn)晦澀難懂,先大致理解概念就行) -
sMainLooper屬性,應(yīng)用程序的主Looper -
mQueue屬性,Looper內(nèi)部維護(hù)的消息隊(duì)列 -
mThread屬性,Looper所在的線程,即我們熟悉的UI線程(主線程)
好了,回到上面的方法流程:
prepareMainLooper() 調(diào)用了 prepare(false) 方法創(chuàng)建了一個(gè)不允許消息隊(duì)列退出的 Looper (主線程 Looper 當(dāng)然不允許退出,只要應(yīng)用程序還在執(zhí)行就會(huì)一直拉取消息或者阻塞,消息隊(duì)列都沒了去哪里拉?。浚?,并將這個(gè) Looper 復(fù)制給了本地線程局部變量 sThreadLocal 。隨后設(shè)置主線程的 Looper 為剛才我們創(chuàng)建的 Looper。
注意:
throw new RuntimeException("Only one Looper may be created per thread")這個(gè)異常,每個(gè)線程中只能存在一個(gè)Looper,每個(gè)線程中只能存在一個(gè)Looper,每個(gè)線程中只能存在一個(gè)Looper(重要的事情說三遍)
Looper.prepareMainLooper() 方法執(zhí)行完后,主線程的 Looper 就準(zhǔn)備就緒了,接下來看看 Looper.loop() 在干什么:
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
//從該線程中取出對(duì)應(yīng)的 Looper 對(duì)象
final Looper me = myLooper();
if (me == null) {
//這里可以看到,必須先調(diào)用 Looper.prepare() 初始化
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
// 拿到Looper 對(duì)象維護(hù)的消息隊(duì)列
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
//重點(diǎn) 重點(diǎn) 重點(diǎn)
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
//調(diào)用消息綁定的Handler進(jìn)行消息處理
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
檢查和判斷后,便開啟了一個(gè)死循環(huán)遍歷消息,并調(diào)用 Handler 的 dispatchMessage(msg) 方法進(jìn)行消息處理,這個(gè)我們上面追蹤 Handler 的時(shí)候也提到了。至此 Looper 的工作便是正式開啟了,一直到程序運(yùn)行結(jié)束。
之前面試被問到:
Looper.loop()既然是開啟了一個(gè)死循環(huán),為什么沒有把程序給搞死? 這是因?yàn)楫?dāng)MessageQueue里有消息的時(shí)候,Looper會(huì)一直循環(huán)取消息,當(dāng)
MessageQueue為空的時(shí)候,Looper所在的線程就會(huì)阻塞,直到再有消息進(jìn)入消息隊(duì)列,Looper會(huì)再次被喚醒
要終止 Looper 循環(huán)取消息,可以調(diào)用 quit() 方法終止 loop()
//////////////////////////////////////// 華麗的分割線 ////////////////////////////////////////
//////////////////////////////////////// 華麗的分割線 ////////////////////////////////////////
//////////////////////////////////////// 華麗的分割線 ////////////////////////////////////////
Message
所在包:package android.os
Message 的源碼相對(duì)來說要簡(jiǎn)單一些,主要包括了 Message 的創(chuàng)建,消息內(nèi)容和信息的設(shè)置以及消息回收,這里簡(jiǎn)單介紹 Message 消息內(nèi)容的設(shè)置,先來看它的幾個(gè)屬性:
/**
* User-defined message code so that the recipient can identify
* what this message is about. Each {@link Handler} has its own name-space
* for message codes, so you do not need to worry about yours conflicting
* with other handlers.
*/
public int what;
/**
* arg1 and arg2 are lower-cost alternatives to using
* {@link #setData(Bundle) setData()} if you only need to store a
* few integer values.
*/
public int arg1;
/**
* arg1 and arg2 are lower-cost alternatives to using
* {@link #setData(Bundle) setData()} if you only need to store a
* few integer values.
*/
public int arg2;
/**
* An arbitrary object to send to the recipient. When using
* {@link Messenger} to send the message across processes this can only
* be non-null if it contains a Parcelable of a framework class (not one
* implemented by the application). For other data transfer use
* {@link #setData}.
*
* <p>Note that Parcelable objects here are not supported prior to
* the {@link android.os.Build.VERSION_CODES#FROYO} release.
*/
public Object obj;
注釋也描述的很清楚了
-
whatint類型,可以用作消息唯一標(biāo)識(shí),或自行指定消息類型 -
arg1,arg2int類型,可以保存一些int型數(shù)據(jù)信息 -
objectObject類型,這里就可以保存你想讓Message攜帶的各種類型信息了
這些都是公共屬性,直接訪問和復(fù)制都可以
除了上面這些公共的屬性,Message 還又如下屬性:
/*package*/ int flags;
/*package*/ long when;
/*package*/ Bundle data;
/*package*/ Handler target;
/*package*/ Runnable callback;
// sometimes we store linked lists of these things
/*package*/ Message next;
-
flagsint型 ,用于給消息做一些標(biāo)記 -
dataBundle類型,可以通過getData()和setData(Bundle data)來獲取和設(shè)值 -
whenlong類型,有沒有覺得有點(diǎn)熟悉?因?yàn)槲覀冊(cè)?Handler消息發(fā)送的時(shí)候說到過,通常用它來記錄消息發(fā)送的延時(shí)時(shí)間 -
target指定消息發(fā)送和處理的Handler,即消息的來源和去向 -
callbackRunnable自定義消息回調(diào)
That`s all 如有遺漏,以后再補(bǔ)充..........