Handler 我必須知道的一切

Android提供的 Handler 消息收發(fā)處理機(jī)制,其根本目的就是解決多線程并發(fā)的問題,與之關(guān)聯(lián)的 Looper,MessageMessageQueue,無論是日常開發(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ù) msguptimeMillis 與消息隊(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 到底有什么作用?

首先得知道,CallbackHandler 內(nèi)部的一個(gè)接口,它包含一個(gè)返回 boolean 值的 handleMessage(Message msg) 方法,區(qū)別于 HandlerhandleMessage(Message msg)(這個(gè)是不帶返回值的)

public interface Callback {
    public boolean handleMessage(Message msg);
}

來創(chuàng)建一個(gè)帶 Callbackhandler

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í)候用到的,先來看一下 HandlerhandleMessage(Message msg) 方法(),它負(fù)責(zé)處理接收到的消息,也是我們經(jīng)常需要重寫的方法,那 HandlerhandleMessage(Message msg) 是怎么被觸發(fā)的,答案就在 Looper 的死循環(huán)中 --> msg.target.dispatchMessage(msg)(后面詳解)
Messagetarget 上面已經(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)用 HandlerhandleMessage(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è) RunnableHandler 自己幫我們把它封裝成了 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)去看一下(ActivityThreadmain() 方法)

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() 方法)拉取 MessageQueueLooper 對(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)用 HandlerdispatchMessage(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;

注釋也描述的很清楚了

  • what int 類型,可以用作消息唯一標(biāo)識(shí),或自行指定消息類型
  • arg1,arg2 int類型,可以保存一些 int 型數(shù)據(jù)信息
  • object Object類型,這里就可以保存你想讓 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;
  • flags int 型 ,用于給消息做一些標(biāo)記
  • data Bundle 類型,可以通過 getData()setData(Bundle data) 來獲取和設(shè)值
  • when long 類型,有沒有覺得有點(diǎn)熟悉?因?yàn)槲覀冊(cè)?Handler 消息發(fā)送的時(shí)候說到過,通常用它來記錄消息發(fā)送的延時(shí)時(shí)間
  • target 指定消息發(fā)送和處理的 Handler,即消息的來源和去向
  • callback Runnable 自定義消息回調(diào)

That`s all 如有遺漏,以后再補(bǔ)充..........

最后編輯于
?著作權(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),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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