Android Handler/Looper/MessageQueue異步消息處理機(jī)制源碼剖析

Android的View模型采用的是單線程模型,所有的視圖相關(guān)的操作都必須在主線程中進(jìn)行,否則會拋出異常。某些耗時的操作需要放入工作線程中,執(zhí)行完后通過異步消息處理機(jī)制把結(jié)果傳入主線程中進(jìn)行刷新UI等操作。異步消息處理機(jī)制主要由Handler\Looper\MessageQueue\Message幾個類,它工作的原理網(wǎng)上有很多資料,這里不再贅述。接下來深入剖析下相關(guān)源碼(源碼基于android8.0)。

1. Message

Message顧名思義,是一個消息,是多線程間通信的實(shí)體,是Handler發(fā)送和處理的對象。Message對象實(shí)現(xiàn)了Parcelable接口,說明Message對象支持序列化/反序列化操作。

成員變量
//標(biāo)識消息的code
public int what;
//存儲int類型的數(shù)據(jù)域
public int arg1;
//存儲int類型的數(shù)據(jù)域
public int arg2;
//存儲對象的數(shù)據(jù)域
public Object obj;
//消息標(biāo)識,當(dāng)消息被回收放入到消息池時會被打上FLAG_IN_USE標(biāo)識
/*package*/
int flags;
//記錄消息的時間戳
/*package*/
long when;
//Bundle數(shù)據(jù)域
/*package*/
Bundle data;
//發(fā)送和處理消息的Handler
/*package*/
Handler target;
//回調(diào)接口,消息可以被Handler處理,也可以被自身的Runnable對象處理
/*package*/
Runnable callback;

// 鏈?zhǔn)浇Y(jié)構(gòu),指向下一個Massgage對象,用于維護(hù)鏈表結(jié)構(gòu)的消息池
/*package*/
Message next;
//靜態(tài)域,信號量,可理解成這個對象是為了同步加鎖創(chuàng)建的,所有需要對消息池進(jìn)行的操作,會對該對象進(jìn)行加鎖同步
private static final Object sPoolSync = new Object();
//靜態(tài)域,鏈表結(jié)構(gòu)消息池的表頭,由它維護(hù)了一個鏈?zhǔn)娇臻e消息池,當(dāng)消息被回收的時候,會加入到這個消息池中
private static Message sPool;
//靜態(tài)域,消息池大小
private static int sPoolSize = 0;
//消息池最大容量是50
private static final int MAX_POOL_SIZE = 50;
//在回收消息之前是否需要檢查消息是否是在被使用當(dāng)中
private static boolean gCheckRecycle = true;

從Message定義的這些變量可知以下幾點(diǎn):

  • Message中分別定義了幾個數(shù)據(jù)域,可以用來存儲數(shù)據(jù)(arg1,arg2,obj,data)。
  • Message中維護(hù)了一個全局的消息池,消息池的最大容量是50
obtain()方法

通過Meaasge.obtain()可以獲得一個Message對象:

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();
}

獲取一個Message對象的源碼很簡單,先加鎖,如果消息池是空的,直接new一個新的Message對象出來,否則從鏈表頭取出一個Message對象,把它暫時從消息池中刪除,并清除它的flag。需要注意的是,obtain靜態(tài)方法有很多重載的實(shí)現(xiàn),但都是先調(diào)用Meaasge.obtain()方法獲取到一個Message對象,再對相關(guān)變量進(jìn)行賦值。

recycle()方法

在一個Message被使用完以后,調(diào)用recycle()方法會被回收:

public void recycle() {
    if (isInUse()) {
        if (gCheckRecycle) {
            throw new IllegalStateException("This message cannot be recycled because it " + "is still in use.");
        }
        return;
    }
    recycleUnchecked();
}

/**
     * Recycles a Message that may be in-use.
     * Used internally by the MessageQueue and Looper when disposing of queued Messages.
     */
void recycleUnchecked() {
    // Mark the message as in use while it remains in the recycled object pool.
    // Clear out all other details.
    flags = FLAG_IN_USE;
    what = 0;
    arg1 = 0;
    arg2 = 0;
    obj = null;
    replyTo = null;
    sendingUid = -1;
    when = 0;
    target = null;
    callback = null;
    data = null;

    synchronized(sPoolSync) {
        if (sPoolSize < MAX_POOL_SIZE) {
            next = sPool;
            sPool = this;
            sPoolSize++;
        }
    }
}

recycle()方法其實(shí)調(diào)用的是recycleUnchecked()方法,在這個方法中,會將flag標(biāo)記為FLAG_IN_USE,并把所有的域清空,并在消息池沒有達(dá)到最大限定值的情況下,把這個對象插入消息池的表頭。同樣,在操作消息池的時候需要先對sPoolSync信號量加鎖。
Message除了上述關(guān)鍵的方法以外,還有一些setter/getter、toString()方法、設(shè)置消息flag、判斷消息flag和實(shí)現(xiàn)Parceable接口的方法,具體不再分析,感興趣的同學(xué)可以自行去查看。


2.MessageQueue

MessageQueue是消息處理隊(duì)列,在異步消息處理中,需要調(diào)用enqueueMessage()方法將消息入隊(duì)到MessageQueue中,然后通過next()方法取出,交給Handler去處理消息。MessageQueue的類由final修飾,禁止對其進(jìn)行繼承、修改。

成員變量

下面來看MessageQueue中定義的成員變量變量:

// True if the message queue can be quit.
private final boolean mQuitAllowed;

@SuppressWarnings("unused") private long mPtr; // used by native code
Message mMessages;
private final ArrayList < IdleHandler > mIdleHandlers = new ArrayList < IdleHandler > ();
private SparseArray < FileDescriptorRecord > mFileDescriptorRecords;
private IdleHandler[] mPendingIdleHandlers;
private boolean mQuitting;
// Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
private boolean mBlocked;

// The next barrier token.
// Barriers are indicated by messages with a null target whose arg1 field carries the token.
private int mNextBarrierToken;
  • mQuitAllowed: 是否允許退出,主線程的MessageQueue在初始化的時候賦值為true,在退出的時候會對其進(jìn)行判斷,如果不允許退出,則拋出異常。
  • mPtr:native層使用的code,暫不做分析;
  • mMessage: 消息隊(duì)列鏈表的表頭,存儲入隊(duì)的消息,取消息的時候也是從它里邊取消息;
  • mIdleHandlers :存放IdleHandler的AarrayList,在消息隊(duì)列中沒有消息或者要處理的消息是在未來才被執(zhí)行時,會去遍歷執(zhí)行mIdleHandlers中的queueIdle()方法;
  • mPendingIdleHandlers:mIdleHandlers中的IdleHandler要執(zhí)行時,會先存放在mPendingIdleHandler中,真正得到執(zhí)行的其實(shí)是這個數(shù)組中的IdleHandler;
  • mQuitting:標(biāo)識MessageQueue是否在執(zhí)行退出,消息隊(duì)列在退出狀態(tài)時不可以再入隊(duì)消息,否則會報(bào)出異常
IdleHandler
public static interface IdleHandler {
    boolean queueIdle();
}

public void addIdleHandler(@NonNull IdleHandler handler) {
    if (handler == null) {
        throw new NullPointerException("Can't add a null IdleHandler");
    }
    synchronized(this) {
        mIdleHandlers.add(handler);
    }
}

public void removeIdleHandler(@NonNull IdleHandler handler) {
    synchronized(this) {
        mIdleHandlers.remove(handler);
    }
}
  

從上述部分源碼知道,IdleHandler是一個接口,可以通過addIdleHandler和removeHandler往mIdleHandlers中添加和移除IdleHandler的實(shí)現(xiàn)類的實(shí)例。

構(gòu)造方法
MessageQueue(boolean quitAllowed) {
    mQuitAllowed = quitAllowed;
    mPtr = nativeInit();
}

MessageQueue的構(gòu)造函數(shù)需要傳入quitAllowed參數(shù),代表是否允許MessageQueue退出。

next()方法
//取出下一個入隊(duì)的消息
Message next() {
    // Return here if the message loop has already quit and been disposed.
    // This can happen if the application tries to restart a looper after quit
    // which is not supported.
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }
    //需要處理的IdleHandler的數(shù)量
    int pendingIdleHandlerCount = -1; // -1 only during first iteration
    int nextPollTimeoutMillis = 0;
    //死循環(huán)去拿Message,直到返回一個Message,或者M(jìn)essageQueue退出
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }

        nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized(this) {
            // Try to retrieve the next message.  Return if found.
            //去拿一個消息,拿到后return
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            //拿到隊(duì)頭,如果拿到的是一個屏障
            //(或者叫攔截器,target一定為null,arg1里保存著屏障的token),
            //則往后遍歷隊(duì)列,直到拿到一個異步消息
            Message msg = mMessages;
            if (msg != null && msg.target == null) {
                // Stalled by a barrier.  Find the next asynchronous message in the queue.
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while ( msg != null && ! msg . isAsynchronous ());
            }
            if (msg != null) {
                if (now < msg.when) {
                    // Next message is not ready.  Set a timeout to wake up when it is ready.
                    //如果拿到的消息的執(zhí)行時間未到,更新nextPollTimeoutMills
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // Got a message.
                    mBlocked = false;
                    if (prevMsg != null) {
                        //preMsg不為空,說明此時隊(duì)列頭是一個barrier,msg此時是異步消息。
                        //preMsg是msg的前驅(qū)節(jié)點(diǎn),把msg從隊(duì)列中刪除
                        prevMsg.next = msg.next;
                    } else {
                        //此時Msg依舊為隊(duì)頭,所以只需要將頭結(jié)點(diǎn)刪掉即可
                        mMessages = msg.next;
                    }
                    //將取出的消息的next域置為null
                    msg.next = null;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    //把消息msg打上FLAG_IN_USE操作,使用的是位或運(yùn)算
                    msg.markInUse();
                    return msg;
                }
            } else {
                // No more messages.
                nextPollTimeoutMillis = -1;
            }

            // Process the quit message now that all pending messages have been handled.
            if (mQuitting) {
                dispose();
                return null;
            }

            // If first time idle, then get the number of idlers to run.
            // Idle handles only run if the queue is empty or if the first message
            // in the queue (possibly a barrier) is due to be handled in the future.
            //如果隊(duì)列為空或者隊(duì)頭的消息沒有到執(zhí)行時間(在未來執(zhí)行),
            //則執(zhí)行idleHandlers的queueIdle()
            if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount <= 0) {
                // No idle handlers to run.  Loop and wait some more.
                //沒有IdleHandlers需要被執(zhí)行,則繼續(xù)for循環(huán),直到拿到消息
                mBlocked = true;
                continue;
            }

            if (mPendingIdleHandlers == null) {
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
            }
            //把mIdleHanders的內(nèi)容復(fù)制到mPendingIdleHandlers的數(shù)組中,等待被執(zhí)行
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }

        // Run the idle handlers.
        // We only ever reach this code block during the first iteration.
        //遍歷pendingIdleHandler數(shù)組,依次執(zhí)行IdleHandler.queueIdle()方法
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null; // release the reference to the handler
            boolean keep = false;
            try {
                //執(zhí)行queueIdle()
                keep = idler.queueIdle();
            } catch(Throwable t) {
                Log.wtf(TAG, "IdleHandler threw exception", t);
            }

            //如果queueIdle()的執(zhí)行結(jié)果為false,
            //則把對應(yīng)的IdleHandler從mIdleHandlers中移除,
            //否則,下次隊(duì)列空閑的時候,還會把mIdleHandlers的
            //內(nèi)容復(fù)制到mPendingIdleHandlers中再次執(zhí)行;
            if (!keep) {
                synchronized(this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }

        // Reset the idle handler count to 0 so we do not run them again.
        //執(zhí)行完以后把變量置0
        pendingIdleHandlerCount = 0;

        // While calling an idle handler, a new message could have been delivered
        // so go back and look again for a pending message without waiting.
        nextPollTimeoutMillis = 0;
    }
}

針對next()方法需要說明以下幾點(diǎn):

  • next方法是從消息隊(duì)列中取出一個可以被執(zhí)行的消息,并將其從隊(duì)列中刪除;如果隊(duì)列為空,或者隊(duì)頭的消息還未到執(zhí)行時間(需要在未來才執(zhí)行),則會執(zhí)行mIdleHandlers中的空閑隊(duì)列IdleHandler.queueIdle()方法;
  • next()方法在執(zhí)行時,如果遇到當(dāng)前隊(duì)列確實(shí)為空時,會去執(zhí)行空閑隊(duì)列,但是不會退出循環(huán),也不會返回null,直到返回一個Messsage對象,或者M(jìn)essageQueue退出,所以可以根據(jù)next()返回的null來判斷MessageQueue是否退出了;
  • IdleHandler.queueIdle()方法的返回值代表是否要保留這個IdleHandler,true為保留,再下次執(zhí)行空閑隊(duì)列時會再次被執(zhí)行,除非手動remove掉這個IdleHandler;false為不保留,執(zhí)行一次則會被移除。可以利用這個來優(yōu)化頁面啟動,把頁面啟動時比較復(fù)雜的邏輯利用IdleHandler去做,這樣可以讓主線程先處理完UI相關(guān)的事件后再去處理負(fù)責(zé)的邏輯,可以減少頁面啟動白屏?xí)r間。
  • Android消息處理機(jī)制中增加了Barrier機(jī)制,稱作屏障或者攔截器、監(jiān)視器,設(shè)置它的目的在于區(qū)分同步消息和異步消息。為了讓View能夠快速的布局和繪制,當(dāng)View在繪制和布局時會向Looper中添加了Barrier,這樣后續(xù)的消息隊(duì)列中的同步的消息將不會被執(zhí)行,以免會影響到UI繪制,但是只有異步消息才能被執(zhí)行。當(dāng)不設(shè)置Barrier時,消息的同步和異步?jīng)]有任何區(qū)別,都是依次按照when的時間先后被執(zhí)行,但是假如Barrier時,隊(duì)列中就只執(zhí)行異步消息,直到我們調(diào)用removeBarrier移除了這個Barrier。
  • 消息默認(rèn)是同步消息(flag默認(rèn)是0,1<<1代表消息是異步消息),調(diào)用Message的setAsynchronous可以把消息變?yōu)楫惒较?,但是這個方法是Hide的,只能由Handler去調(diào)用,在構(gòu)造Handler時,需要傳入是否為異步消息的變量,具體源碼下邊分析;
  • 針對隊(duì)列的操作,進(jìn)行了同步操作,在操作隊(duì)列之前,先進(jìn)行了加鎖,所以MessageQueue是線程安全的消息隊(duì)列;
enqueueMessage()方法
boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
           //入隊(duì)的消息的target,必須不為空,否則會拋異常
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            //消息在回收之前,不可以被重復(fù)使用
            throw new IllegalStateException(msg + " This message is already in use.");
        }
       //加鎖同步
        synchronized (this) {
            if (mQuitting) {
                 //如果消息隊(duì)列在退出狀態(tài) ,則直接回收消息,返回false
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }
           //把消息標(biāo)記為在使用狀態(tài),設(shè)置when
            msg.markInUse();
            msg.when = when;
           //此時p指向鏈表頭
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                //如果隊(duì)列為空或者when等于0,或者when小于
                //隊(duì)頭Message的when,則直接把消息插入隊(duì)頭
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                   //prev是p的前驅(qū)節(jié)點(diǎn),依次遍歷
                    prev = p;
                    p = p.next;
                    //當(dāng)p已經(jīng)到隊(duì)尾或者找到一個節(jié)點(diǎn)msg.when < p.when時退出循環(huán)
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
               //鏈表插入操作,把msg插入到p節(jié)點(diǎn)前邊,并把p的前驅(qū)節(jié)點(diǎn)的next改為msg
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        //插入成功,返回true
        return true;
    }

針對消息入隊(duì)函數(shù)enqueueMessage()方法,需要說明以下幾點(diǎn):

  • 該方法對鏈表隊(duì)列操作時,依然是進(jìn)行了加鎖同步,所以是線程安全的;
  • 返回值true代表入隊(duì)成功,false代表入隊(duì)失敗,在隊(duì)列已經(jīng)退出狀態(tài)時再次入隊(duì)消息會返回false;
  • 隊(duì)列是根據(jù)when值(也就是所謂的消息執(zhí)行時間)大小組成的一個升序鏈表,插入也必須找到合適的節(jié)點(diǎn)進(jìn)行插入,所以next遍歷消息的時候,只需要看隊(duì)頭消息的when是否到執(zhí)行時間就可以判斷是否需要執(zhí)行mIdleHandlers里的空閑隊(duì)列;
quit()方法
void quit(boolean safe) {
    if (!mQuitAllowed) {
        //如果不允許退出,調(diào)用該方法,會拋出異常
        throw new IllegalStateException("Main thread not allowed to quit.");
    }
    //對自身進(jìn)行加鎖同步
    synchronized(this) {
        //如果已經(jīng)是退出狀態(tài)了,再次退出,直接返回
        if (mQuitting) {
            return;
        }
        //把mQuitting置為true,標(biāo)識隊(duì)列已經(jīng)退出。一旦隊(duì)列
        //是退出狀態(tài),則無法再次使用,除非再次new一個MessageQueue
        mQuitting = true;
        //參數(shù)safe標(biāo)識是否為安全退出,ture會將還未到執(zhí)行時間的Message
        //(在未來時刻執(zhí)行)remove掉并清除Message的內(nèi)容;false會移除
        //全部Message并清除Message的內(nèi)容
        if (safe) {
            removeAllFutureMessagesLocked();
        } else {
            removeAllMessagesLocked();
        }

        // We can assume mPtr != 0 because mQuitting was previously false.
        nativeWake(mPtr);
    }
}

private void removeAllFutureMessagesLocked() {
    final long now = SystemClock.uptimeMillis();
    Message p = mMessages;
    if (p != null) {
        //如果隊(duì)頭的執(zhí)行時間已經(jīng)是在未來時刻了,則直接調(diào)用
        //removeAllMessagesLocked()方法清除所有的消息
        if (p.when > now) {
            removeAllMessagesLocked();
        } else {
            Message n;
            //for循環(huán)找出Message的執(zhí)行時間大于now的節(jié)點(diǎn),
            //退出循環(huán)
            for (;;) {
                n = p.next;
                if (n == null) {
                    return;
                }
                if (n.when > now) {
                    break;
                }
                p = n;
            }
            p.next = null;
            //while循環(huán)遍歷,調(diào)用Message.recycleUncheked()方法
            //清除消息內(nèi)容,并從隊(duì)列中刪除
            do {
                p = n;
                n = p.next;
                p.recycleUnchecked();
            } while ( n != null );
        }
    }
}
//循環(huán)遍歷,清除消息隊(duì)列中所有Message的內(nèi)容并從隊(duì)列中刪除
private void removeAllMessagesLocked() {
    Message p = mMessages;
    while (p != null) {
        Message n = p.next;
        p.recycleUnchecked();
        p = n;
    }
    mMessages = null;
}

  • 參數(shù)safe表示是否需要安全退出,true則會把未執(zhí)行(Message.when > now)的消息全部清除并刪除,待執(zhí)行的Message會繼續(xù)執(zhí)行完;false會直接把隊(duì)列中所有的Message給清除并刪除;
  • 退出操作依然進(jìn)行了同步操作,屬于線程安全的;
  • 如果隊(duì)列quitAllowed為false,表示不允許退出,如果強(qiáng)行退出,會拋出異常;一旦退出,隊(duì)列無法再次被使用;

MessageQueue里還有判斷隊(duì)列中是否有特定消息和移除特定消息的一系列重載方法、一些native方法等,有興趣的同學(xué)可以去看下,這里不再分析。


3.Handler

Handler是消息分發(fā)對象,可以發(fā)送Message和處理Message。

成員變量
//j是否發(fā)現(xiàn)潛在的內(nèi)存泄漏,默認(rèn)為false
private static final boolean FIND_POTENTIAL_LEAKS = false;
private static final String TAG = "Handler";
//靜態(tài)全局變量,主線程的Handler
private static Handler MAIN_THREAD_HANDLER = null;

//綁定的Looper對象
final Looper mLooper;
//綁定的MessageQueue消息隊(duì)列
final MessageQueue mQueue;
//回調(diào)接口的實(shí)現(xiàn)
final Callback mCallback;
//是否是異步的,如果是異步的,在發(fā)送消息的時候,
//會調(diào)用Message.setAsynchronous(true)把消息設(shè)為異步消息
final boolean mAsynchronous;
IMessenger mMessenger;
  • 一個Handler與一個Looper和MessageQueue相關(guān)聯(lián)
Callback、dispatchMessage()方法
public interface Callback {
    /**
         * @param msg A {@link android.os.Message Message} object
         * @return True if no further handling is desired
         */
    public boolean handleMessage(Message msg);
}

/**
     * Subclasses must implement this to receive messages.
     */
public void handleMessage(Message msg) {}

/**
     * Handle system messages here.
     */
public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

private static void handleCallback(Message message) {
    message.callback.run();
}
  • Callback是一個接口,可以在Handler對象初始化的時候把一個Callback對象傳進(jìn)去;
  • 可以看出dispatchMessage處理消息的優(yōu)先級順序依次是
    • 如果Message本身設(shè)置了Callback(是一個Runnable對象),則把Message交給Message自身的Callback來處理;
    • 否則,如果Handler的設(shè)置了Callback回調(diào)(是Handler.Callback的實(shí)現(xiàn)類),則由Handler的Callback來處理,并返回一個返回值,表示是否消耗掉這個消息,不進(jìn)行后續(xù)處理(有點(diǎn)類似于消息傳遞機(jī)制的返回值);
    • 如果上一步的返回值是false,則表示不消耗這個消息,交給Handler本身的handleMessage方法來處理,這個方法默認(rèn)實(shí)現(xiàn)是空方法,需要自行覆寫去處理消息;
構(gòu)造函數(shù)
public Handler() {
    this(null, false);
}

public Handler(Callback callback) {
    this(callback, false);
}

public Handler(Looper looper) {
    this(looper, null, false);
}

public Handler(Looper looper, Callback callback) {
    this(looper, callback, false);
}

public Handler(boolean async) {
    this(null, async);
}

public Handler(Callback callback, boolean async) {
    if (FIND_POTENTIAL_LEAKS) {
        //如果FIND_POTENTIAL_LEAKS設(shè)為true,如果Handler自身對象是匿名類、內(nèi)部成員
        //類和本地類而且不是static的時候,會給出警告,可能有潛在的內(nèi)存泄漏風(fēng)險(xiǎn)
        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());
        }
    }
    //調(diào)用Looper.myLooper()方法獲得一個Looper對象,源碼下文分析
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");
    }
    //MessageQueue直接拿Looper對象里的mQueue對象
    mQueue = mLooper.mQueue;
    mCallback = callback;
    //設(shè)置是否異步
    mAsynchronous = async;
}

public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}
  • 第6個重載方法,調(diào)用Looper.myLooper()方法獲得一個Looper對象,并從Looper對象里直接拿mQueue賦值給自身對象的mQueue;
  • 構(gòu)造方法重載中,有可以直接設(shè)置Looper對象的,不一定是非得通過Looper.myLooper()來初始化mLooper對象,也有可能是外部獲得了直接傳進(jìn)來;
  • 如果FIND_POTENTIAL_LEAKS設(shè)為true,如果Handler自身對象是匿名類、內(nèi)部成員類和本地類而且不是static的時候,會給出警告,可能有潛在的內(nèi)存泄漏風(fēng)險(xiǎn),所以建議Handler如果是內(nèi)部類的時候,建議使用靜態(tài)內(nèi)部類;
obtainMessage()方法
public final Message obtainMessage() {
    return Message.obtain(this);
}
  • Handler中有一系列obtanMessage()重載方法,只是傳的參數(shù)不同,其實(shí)最后調(diào)用的還是Message.obtain()方法,需要注意的是,在Message中,obtain()方法是靜態(tài)方法,在Handler中,是非靜態(tài)的,需要通過具體的Handler實(shí)例對象來獲得,但是禁止子類進(jìn)行覆寫;
post(Runnable r)相關(guān)方法

在Handler中,可以發(fā)送一個Runnable對象,也可以發(fā)送一個Message對象,現(xiàn)在我們先來分析發(fā)送Runnable對象的相關(guān)方法:

//立即post一個Runnable到MessageQueue中,此時Runnable被包裝正Message后放在MessageQueue隊(duì)列中(when == 當(dāng)前系統(tǒng)時間,可能是隊(duì)頭,也可能不是隊(duì)頭,隊(duì)列中已經(jīng)有when值小于當(dāng)前時間的Message)
public final boolean post(Runnable r) {
    return sendMessageDelayed(getPostMessage(r), 0);
}
//Runnable包裝成Message后加入到MessageQueue中,但此時
//Message.when=uptimeMillis,uptimeMills是消息的執(zhí)行時間,
//即指定了具體的執(zhí)行系統(tǒng)時間
public final boolean postAtTime(Runnable r, long uptimeMillis) {
    return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
//同上,只是又傳入了token對象,存儲在Message.obj中
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis) {
    return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}
//Runnable包裝成Message后加入到MessageQueue中,
//但是Message.when等于當(dāng)前時間+delayMillis,
//表示延遲delayMills后執(zhí)行
public final boolean postDelayed(Runnable r, long delayMillis) {
    return sendMessageDelayed(getPostMessage(r), delayMillis);
}
//Runnable包裝成Message后加入到MessageQueue中,此時when=0,
//一定是在MessageQueue的隊(duì)頭
public final boolean postAtFrontOfQueue(Runnable r) {
    return sendMessageAtFrontOfQueue(getPostMessage(r));
}
//把Runnable對象包裝成Message對象,可見只是把Runnable對象
//賦值給了Message的callback域
private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}
//上述方法的重載方法,把token賦值給了Message的obj域,
//可以用這個方法進(jìn)行傳值
private static Message getPostMessage(Runnable r, Object token) {
    Message m = Message.obtain();
    m.obj = token;
    m.callback = r;
    return m;
}
//延遲發(fā)送,把當(dāng)前時間加上延遲時間后調(diào)用了sendMessageAtTime()方法
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
//發(fā)送消息的方法,對queue判空后,調(diào)用enqueueMessage進(jìn)行實(shí)際入隊(duì)
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
    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);
}
//實(shí)際對消息入隊(duì)的方法,在該方法中,會把Message的target域進(jìn)行賦值,
//如果mAsynchronous是true,則會調(diào)用setter方法把消息設(shè)置為異步消息,
//調(diào)用的入隊(duì)方法其實(shí)是調(diào)用的MessageQueue的enqueueMessage方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}
  • post相關(guān)方法傳入的是Runnable對象,但是最終都會被包裝成Message對象,通過obtain()獲取一個Message對象,即把Runnable對象傳入Message的callback域,并可以傳入一個Object對象到Message的obj域進(jìn)行傳值;
  • 發(fā)送消息其實(shí)就是把消息入隊(duì),實(shí)際的入隊(duì)操作其實(shí)是調(diào)用的MessageQueue對象的enqueueMessage操作,一系列的調(diào)用方法只是在計(jì)算Message的when值;
  • 調(diào)用post()后,不一定消息就在MessageQueue的隊(duì)頭,也就意味著post的Runnable不一定會立即得到執(zhí)行,因?yàn)榇藭r消息的when值是當(dāng)前的系統(tǒng)時間,不能保證它前邊沒有在等待執(zhí)行的消息;如果想要立即被執(zhí)行,可以調(diào)用postAtFrontOfQueue(Runnable r)方法;
  • 在實(shí)際的入隊(duì)方法enqueueMessage()中,會將傳入的Message對象的target對象賦值為自身的引用,如果mAsynchronous是true,則會調(diào)用setter方法把消息設(shè)置為異步消息,最后調(diào)用的MessageQueue的enqueueMessage方法對消息進(jìn)行入隊(duì)操作;上邊講到的MessageQueue中異步消息標(biāo)志位,就是在這設(shè)置位ture的;
sendMessage(Message msg)相關(guān)方法
public final boolean sendMessage(Message msg) {
    return sendMessageDelayed(msg, 0);
}

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);
}
//...
//省略其他方法,基本上跟post系列方法是一一對應(yīng)的
  • sendMessage方法的參數(shù)是Message對象,跟post系列方法的區(qū)別就是不用把Runnable封裝成Message,其實(shí)調(diào)用鏈最后都是 sendMessageAtTime() -> enqueueMessage();
  • sendMessage方法和post方法的區(qū)別在于對消息的處理不同:
    • post一個Runnable的時候,由于把Runnable對象賦值給了callback域,所以在Looper調(diào)用dispatchMessage()方法的時候,這個Runnable對象直接得到了執(zhí)行;而sendMessage系列的方法把消息發(fā)送后,在Looper調(diào)用dispatchMessage()方法的時候,由于Message的callback域可能為空,需要給Handler設(shè)置callback或者覆寫handlerMessage(Message msg)來處理消息;
    • 我的理解是,post系列方法側(cè)重是想把某些操作給post到特定線程去執(zhí)行,而sendMessage系列的方法是想把值傳到特定線程,然后針對特定值去做某些處理;所以,post方法弱化傳值的操作,sendMessage方法強(qiáng)調(diào)的是傳值并對傳過去的值進(jìn)行操作;
runWithScissors(final Runnable r, long timeout)

除了post(Runnable r)系列方法和sendMessage(Message msg)系列方法可以發(fā)送消息外,還有runWithScissors可以發(fā)送消息(Runnable對象)。

/**
     * Runs the specified task synchronously.
     * <p>
     * If the current thread is the same as the handler thread, then the runnable
     * runs immediately without being enqueued.  Otherwise, posts the runnable
     * to the handler and waits for it to complete before returning.
     * </p><p>
     * This method is dangerous!  Improper use can result in deadlocks.
     * Never call this method while any locks are held or use it in a
     * possibly re-entrant manner.
     * </p><p>
     * This method is occasionally useful in situations where a background thread
     * must synchronously await completion of a task that must run on the
     * handler's thread.  However, this problem is often a symptom of bad design.
     * Consider improving the design (if possible) before resorting to this method.
     * </p><p>
     * One example of where you might want to use this method is when you just
     * set up a Handler thread and need to perform some initialization steps on
     * it before continuing execution.
     * </p><p>
     * If timeout occurs then this method returns <code>false</code> but the runnable
     * will remain posted on the handler and may already be in progress or
     * complete at a later time.
     * </p><p>
     * When using this method, be sure to use {@link Looper#quitSafely} when
     * quitting the looper.  Otherwise {@link #runWithScissors} may hang indefinitely.
     * (TODO: We should fix this by making MessageQueue aware of blocking runnables.)
     * </p>
     *
     * @param r The Runnable that will be executed synchronously.
     * @param timeout The timeout in milliseconds, or 0 to wait indefinitely.
     *
     * @return Returns true if the Runnable was successfully executed.
     *         Returns false on failure, usually because the
     *         looper processing the message queue is exiting.
     *
     * @hide This method is prone to abuse and should probably not be in the API.
     * If we ever do make it part of the API, we might want to rename it to something
     * less funny like runUnsafe().
     */
public final boolean runWithScissors(final Runnable r, long timeout) {
    if (r == null) {
        throw new IllegalArgumentException("runnable must not be null");
    }
    if (timeout < 0) {
        throw new IllegalArgumentException("timeout must be non-negative");
    }
    //如果當(dāng)前的線程和Handler所在的線程是同一個,則直接運(yùn)行Runnable對象,
    //而不需要再進(jìn)行入隊(duì)-排隊(duì)-出隊(duì)的操作;
    if (Looper.myLooper() == mLooper) {
        r.run();
        return true;
    }
    //如果當(dāng)前線程和Handler的線程不在同一個線程,
    //則會調(diào)用BlockingRunnable的postAndWait()方法
    BlockingRunnable br = new BlockingRunnable(r);
    return br.postAndWait(this, timeout);
}

//靜態(tài)內(nèi)部私有常量類,實(shí)現(xiàn)Runnable接口
private static final class BlockingRunnable implements Runnable {
    //真正需要執(zhí)行的Rnnable對象
    private final Runnable mTask;
    //標(biāo)識是否執(zhí)行完畢
    private boolean mDone;

    public BlockingRunnable(Runnable task) {
        mTask = task;
    }

    @Override public void run() {
        try {
            mTask.run(); //運(yùn)行mTask.Runnalbe
        } finally {
            synchronized(this) {
                //執(zhí)行完以后,會把mDone標(biāo)志位置為true,并喚醒其他阻塞線程
                mDone = true;
                notifyAll();
            }
        }
    }

    public boolean postAndWait(Handler handler, long timeout) {
        //把自身對象通過傳入的handler.post()方法進(jìn)行入隊(duì)操作,
        //入隊(duì)成功返回true,失敗返回false;
        if (!handler.post(this)) {
            return false;
        }
        //加鎖同步
        synchronized(this) {
            if (timeout > 0) {
                //計(jì)算超時時間,如果超時后還沒有執(zhí)行完,返回false,
                //并執(zhí)行run中finally中的操作,
                //即把標(biāo)志位置為true,并喚醒其他線程,此時run可能還沒有執(zhí)行完
                final long expirationTime = SystemClock.uptimeMillis() + timeout;
                while (!mDone) {
                    long delay = expirationTime - SystemClock.uptimeMillis();
                    if (delay <= 0) {
                        return false; // timeout
                    }
                    try {
                        wait(delay);
                    } catch(InterruptedException ex) {}
                }
            } else {
                //如果timeout小于等于0,會阻塞handler所在線程,
                //直到run方法內(nèi)的finallay塊被執(zhí)行(會一直等到run執(zhí)行完畢)
                while (!mDone) {
                    try {
                        wait();
                    } catch(InterruptedException ex) {}
                }
            }
        }
        return true;
    }
} 
  • 這個方法是消息的同步執(zhí)行方法,在執(zhí)行的時候會阻塞handler所在線程。執(zhí)行時可以設(shè)置超時時間,如果超時后,直接喚醒線程,停止執(zhí)行;如果超時時間小于等于0,則會一直等到run執(zhí)行完畢,finally塊得到執(zhí)行才能喚醒線程;
  • runWithScissors()方法的返回值,true代表Runnable對象被正確執(zhí)行,false代表執(zhí)行失??;
  • 源碼注釋寫的很清楚,這個方法非常的危險(xiǎn),不建議使用,因?yàn)椴划?dāng)?shù)氖褂每赡軙?dǎo)致死鎖。不要在持有任何鎖時調(diào)用此方法,也不要以可重入的方式使用它。
  • 在后臺線程必須同步等待在處理程序的線程上運(yùn)行的任務(wù)完成的情況下,這種方法有時很有用。然而,這個問題通常是糟糕設(shè)計(jì)的癥狀。在使用這種方法之前,考慮改進(jìn)設(shè)計(jì)(如果可能的話)。
getMain()方法
/** @hide */
@NonNull public static Handler getMain() {
    if (MAIN_THREAD_HANDLER == null) {
        MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper());
    }
    return MAIN_THREAD_HANDLER;
}

/** @hide */
@NonNull public static Handler mainIfNull(@Nullable Handler handler) {
    return handler == null ? getMain() : handler;
}
  • 通過getMain()方法可以拿到主線程的Handler;
  • mainIfNull(Handler hander)方法,相當(dāng)于是對傳入的handler進(jìn)行判空,如果為空,則返回主線程的Handler;

Handler中還有removeCallbacks()、removeMessage()、hasMessage()、toString()方法以及其重載方法,源碼比較簡單,這里就不做分析了,感興趣的同學(xué)可以自行去查看源碼。


4. Looper

Looper內(nèi)部有一個消息隊(duì)列MessageQueue,循環(huán)從MessageQueue中不斷取出Message并對其進(jìn)行分發(fā)。一個線程只能有一個Looper,由于Looper是線程局部變量,所以每個Looper中又有各自的MessageQueue。

成員變量
// sThreadLocal.get() will return null unless you've called prepare().
//靜態(tài)域,線程局部變量,每個線程中有一個獨(dú)立Looper對象。
//如果不調(diào)用prepare()方法,sThreadLocal.get()返回null
static final ThreadLocal < Looper > sThreadLocal = new ThreadLocal < Looper > ();
//靜態(tài)域,主線程的Looper,由Looper class來維護(hù)
private static Looper sMainLooper; // guarded by Looper.class
//消息隊(duì)列,每個Looper中有一個MessageQueue
final MessageQueue mQueue;
//Looper對象自身所在線程
final Thread mThread;
//打印對象及Tag
private Printer mLogging;
private long mTraceTag;
/* If set, the looper will show a warning log if a message dispatch takes longer than time. */
private long mSlowDispatchThresholdMs;
  • sThreadLocal是一個線程本地變量,每一個線程獨(dú)自維護(hù)各自Looper的值,保證了每個線程都有一個Looper。關(guān)于ThreadLocal線程本地變量的原理這里不多展開講解了,不了解的同學(xué)可以自行查閱資料。這里需要注意,Java的ThreadLocal和Android的ThreadLocal的實(shí)現(xiàn)是不一樣的;
  • 由于sThreadLocal是線程局部變量,Looper中所有的非靜態(tài)變量在每個線程都有單獨(dú)的副本,所以每個線程都有各自的MessageQueue;
  • 初始化的時候,會把Looper所在線程信息記錄在mThread變量中;
構(gòu)造方法
private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}
  • Looper的構(gòu)造方法是私有的,不能new出一個Looper,而是應(yīng)該調(diào)用prepare()方法來獲得一個Looper對象;
  • 構(gòu)造方法很簡單,new了一個MessageQueue,并把當(dāng)前線程信息記錄下來。傳入的參數(shù)quitAllowed代表是否允許MessageQueue退出,如果不允許退出,調(diào)用MessageQueue的quit()方法時會拋出異常;
prepare()方法
//公有方法,開發(fā)者只能調(diào)用這個方法進(jìn)行Looper的初始化,
//可見開發(fā)者得到的Looper中的MessageQueue,是允許退出的
public static void prepare() {
    prepare(true);
}
//私有方法,開發(fā)者無法調(diào)用,而且對同一個線程重復(fù)調(diào)用
//prepare()方法會拋出異常
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));
}
//主線程的Looper初始化,雖然是公有方法,我們無法調(diào)用,
//因?yàn)橄到y(tǒng)啟動的時候已經(jīng)調(diào)用過了,如果再次調(diào)用,會拋異常
public static void prepareMainLooper() {
    prepare(false);
    synchronized(Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        //把得到的主線程Looper賦值給sMainLooper 
        sMainLooper = myLooper();
    }
}
  • 調(diào)用Looper.prepare()會為當(dāng)前線程初始化一個Looper對象,Looper對象又會初始化一個MessageQueue對象;
  • 主線程初始化Looper時創(chuàng)建的MessageQueue對象是禁止退出操作的,而其他線程初始化時Looper創(chuàng)建的MessagQueue是允許退出操作的。
  • 一個線程只能調(diào)用一次prepare()方法,否則會拋出異常,所以在prepare()之前,應(yīng)該先調(diào)用myLooper()方法判斷是否為空;
  • 主線程的Looper在ActivityThread中的main()方法進(jìn)行初始化的,
public static@Nullable Looper myLooper() {
    return sThreadLocal.get();
}
loop()方法
 //代碼省去打印等其他無關(guān)邏輯
public static void loop() {
    //拿到本線程的sThreadLocal變量的值
    final Looper me = myLooper();
    //如果當(dāng)前線程沒有調(diào)用過prepare()方法,則me為null,拋出異常
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    //從me里獲得本線程的MessageQueue對象
    final MessageQueue queue = me.mQueue;
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();
    //進(jìn)入死循環(huán),開始從MessageQueue中取出消息進(jìn)行處理
    for (;;) {
        //取出消息,可能被阻塞
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }
        try {
            //通過Message對象中的targe域獲得發(fā)送該消息的Handler,
            //調(diào)用它的dispatchMessage()方法來處理對象
            msg.target.dispatchMessage(msg);
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
        final long newIdent = Binder.clearCallingIdentity();
        msg.recycleUnchecked();
    }
}
  • 拿到本線程的sThreadLocal變量的值,如果當(dāng)前線程沒有調(diào)用過prepare()方法,則me為null,拋出異常;
  • 從me里獲得本線程的MessageQueue對象,進(jìn)入死循環(huán),開始從MessageQueue中取出消息進(jìn)行處理;
  • 通過Message對象中的targe域獲得發(fā)送該消息的Handler,調(diào)用它的dispatchMessage()方法來處理對象,這也是為什么在入隊(duì)的時候,會對Message的target域進(jìn)行判空;
  • 當(dāng)MessageQueue的next方法返回為null時,意味著MessageQueue已經(jīng)退出了(next()方法有分析),此時會退出死循環(huán),所以MessageQueue的退出,也會導(dǎo)致Looper的循環(huán)結(jié)束;

Looper還有quit(),quitSafely(),toString()等其他方法,感興趣的同學(xué)可以自行查看源碼;


5. 利用異步消息處理機(jī)制,主線程與子線程之間的通信

通過上述源碼的詳細(xì)分析,可以知道:

  • 一個線程只能通過Looper.prepare()(建議不確定子線程是否已經(jīng)調(diào)過了,調(diào)用它之前可以先調(diào)用Looper.myLooper()判斷下,否則會拋異常)來產(chǎn)生一個Looper對象,同時也綁定了一個屬于該線程的MessageQueue對象;
  • 一個Handler在構(gòu)造函數(shù)中,會獲取當(dāng)前線程中的Looper對象,并從Looper對象中獲取MessageQueue對象,所以在new一個Handler之前,要保證Looper.prepare()已經(jīng)調(diào)用過,否則會拋出異常;
  • 一個消息,最終是在哪個線程被處理的,取決于這個Handler在哪個線程(通過new一個Handler方式得到的Looper和MessageQueue是在同一個線程的),最后分發(fā)Message被執(zhí)行的是在Looper.loop()方法的 msg.target.dispatchMessage(msg)語句來處理的,所以消息被拋給Handler去處理,也就是說消息被哪個線程的Handler發(fā)送,就會在哪個線程被執(zhí)行;
  • 基于上述思路,主線程與子線程之間的通信就簡單明了了,子線程向主線程進(jìn)行通信,只需直接在主線程new一個Handler(在主線程中不可以調(diào)用Looper.prepare()方法),然后把消息發(fā)送過去就行:
private static Handler handler = new Handler() {
    //主線程處理消息
    @Override public void handleMessage(Message msg) {
        //主線程根據(jù)Message進(jìn)行邏輯處理
    }
};
class WorkThreadRunnable implements Runnable {
    //子線程發(fā)送相關(guān)消息
    @Override public void run() {
        Message message = Message.obtain();
        //在子線程中用在主線程中創(chuàng)建的Hander發(fā)送消息即可
        handler.sendMessage(message);
    }
}
  • 主線程向子線程進(jìn)行通信,有兩種方式,一種是需要在子線程先調(diào)用Looper.prepare()方法初始化一個Looper和MessageQueue,然后在子線程創(chuàng)建一個Handler,并在主線程使用這個handler進(jìn)行發(fā)送消息,子線程接收到消息后進(jìn)行處理即可:
 private Handler handler;

@Override 
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_handler_main_to_child);
    button = (Button) findViewById(R.id.button);
    button.setOnClickListener(new View.OnClickListener() {@Override public void onClick(View view) {
            Message message = Message.obtain();
            handler.sendMessage(message);
        }
    });
    new Thread(new WorkThreadRunnable()).start();

}

class WorkThreadRunnable implements Runnable {@Override public void run() {
        Looper.prepare();
        handler = new Handler() {@Override public void handleMessage(Message msg) {
                //接收到消息后,進(jìn)行處理
            }
        };
        Looper.loop();
    }
}
  • 主線程向子線程進(jìn)行通信的時候,Handler也不一定非得是在子線程進(jìn)行創(chuàng)建,另一種方式是在子線程創(chuàng)建Looper,在主線程new Handler的時候,把子線程的Looper當(dāng)參數(shù)傳入,這樣新建的Handler與Looper所在線程就進(jìn)行了綁定,這樣,主線程通過這個Handler依然可以向子線程進(jìn)行通信:
     //創(chuàng)建子線程
class WorkThread extends Thread {
    private Looper looper; //取出該子線程的Looper
    public void run() {
        Looper.prepare(); //創(chuàng)建該子線程的Looper
        looper = Looper.myLooper(); //取出該子線程的Looper
        Looper.loop(); //只要調(diào)用了該方法才能不斷循環(huán)取出消息
    }
}

private Handler mHandler;

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    thread = new WorkThread();
    thread.start();
    //創(chuàng)建Handler時把looper做入?yún)?,把Handler與Looper綁定在一起
    mHandler = new Handler(thread.looper) {
        public void handleMessage(android.os.Message msg) {
            //在子線程中處理消息的邏輯
        };
    };
    mHandler.senMessage(Message.obtain());
}
  • 利用HandlerThread也可以實(shí)現(xiàn)線程間的通信,它其實(shí)是Thread和消息處理機(jī)制的一種封裝,后續(xù)文章再進(jìn)行分析

6. 異步消息處理機(jī)制使用不當(dāng)可能導(dǎo)致的問題
內(nèi)存泄漏

通常情況下,我們會在一個Activity/Fragment中使用消息處理機(jī)制進(jìn)行線程間的通信,如果Handler為非靜態(tài)內(nèi)部類,則會引用外部類對象。當(dāng)Activity/Fragment finish時,Handler可能并未執(zhí)行完,則會引起Activity/Fragment的內(nèi)存泄漏。故而所有調(diào)用Handler的地方,都使用靜態(tài)內(nèi)部類。如果Handler需要訪問Activity/Fragemnt非靜態(tài)成員/非靜態(tài)方法,可以讓Handler持有外部對象的弱引用;

private static class HandlerDemo extends Handler{
    private final WeakReference<Activity> mActivity;
    
    public HandlerDemo(Activvity mActivity) {
        this.mActivity = new WeakRefrence<Activity>(mActivity);
    }

   @Override
    public void handleMessage(Message msg) {
          //處理消息,在訪問mActivity的時候要先進(jìn)行判空
    }
}
資源被釋放而導(dǎo)致的異常

當(dāng)Activity/Fragment調(diào)用onDestroy()等回調(diào)方法后,會釋放掉一些資源,而在Handler執(zhí)行handleMessage()方法時,在訪問Activity/Fragment的成員變量/方法時,可能會由于資源被釋放而導(dǎo)致空異常。所以除了在對Activity/Fragment進(jìn)行判空以外,還要對訪問到的成員變量等進(jìn)行判空操作,并且在onDestory()方法里把消息隊(duì)列中的消息remove。

  @Override
  protected onDestroy() {\
      super.onDestory();
      //移除post的Runnable對象
      handler.removeCallback(postRunnable);
      //移除send的Message對象
      handler.removeMessage(what);
  }

7. 總結(jié)

通過上述源碼分析,我們理解了Message、MessageQueue、Handler和Looper的實(shí)現(xiàn)細(xì)節(jié),現(xiàn)在應(yīng)該對Android異步消息處理機(jī)制的實(shí)現(xiàn)的細(xì)節(jié)、通信原理和可能帶來問題都清楚了,如果還有什么疑問,大家可以自行查看源碼。如果有寫的不對的地方,歡迎進(jìn)行指正和交流。

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

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

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