Android源碼分析之消息機(jī)制


說(shuō)明:本文是基于Android6.0源碼來(lái)分析的

  • 這片文章主要是從源碼的角度來(lái)分析Android中的消息機(jī)制是如何運(yùn)行的,并不會(huì)介紹如何使用Handler。
  • Android的消息機(jī)制可以說(shuō)是Android的血液,流淌在不同的app之間,催動(dòng)這各種事件有序的執(zhí)行。
  • Android進(jìn)程在啟動(dòng)的時(shí)候會(huì)調(diào)用ThreadActivity的main方法,從main方法中我們可以看出,Android的app進(jìn)程啟動(dòng)以后只有一個(gè)線程ActivityThread他是main線程,除了創(chuàng)建主線程方法以外,還為我們的主線程準(zhǔn)備了mianLooper,最后開(kāi)啟了一個(gè)Looper 循環(huán)

整個(gè)消息機(jī)制的一個(gè)重要用途,就是線程間通信,而且大部分都是工作線程向主線程發(fā)送數(shù)據(jù)和消息。那么為什么Android系統(tǒng)要這樣設(shè)計(jì)呢?其實(shí)典型的Android應(yīng)用,都是事件驅(qū)動(dòng)的GUI程序,跟Window的GUI程序很類似。這種程序,特點(diǎn)就是基于事件運(yùn)行,比如點(diǎn)擊事件或者滑動(dòng)事件。所以這種情況下,肯定是要有一個(gè)專門的線程來(lái)負(fù)責(zé)事件的監(jiān)聽(tīng)和分發(fā)。在Android中,系統(tǒng)默認(rèn)啟動(dòng)的主線程,就干這個(gè)事情了。
由于該消息分發(fā)線程有著自己獨(dú)特的任務(wù),所以如果該線程阻塞了的話,系統(tǒng)就會(huì)出現(xiàn)無(wú)響應(yīng)的情況。這樣,自然就不可能把耗時(shí)的任務(wù)放在該線程中,所以官方推薦是把耗時(shí)的任務(wù)放到工作線程中執(zhí)行。但是很多時(shí)候,耗時(shí)任務(wù)的執(zhí)行結(jié)果,都是要反饋到UI上的。而Android中的View,是不能在非UI線程中更新的,因?yàn)閂iew不是線程安全的,沒(méi)有同步,所以必須要把數(shù)據(jù)通過(guò)線程間通信的模式,發(fā)送到UI線程,這能才可以正常更新UI。

所以大家會(huì)問(wèn),Android為什么不把View設(shè)計(jì)成線程安全的呢?那么在Java這種指令式編程語(yǔ)言中,線程安全就是意味著要加鎖。其實(shí)我們可以思考一下,整個(gè)View響應(yīng)事件,事件從屏幕產(chǎn)生,經(jīng)過(guò)Framework,最后到kernel,然后kernel處理完成后,向上傳遞到framework,然后又傳遞到View層。如下圖所示:
那么如果整個(gè)流程都是線程安全的話,就會(huì)面臨著兩個(gè)相對(duì)的加鎖流程,這種反方向的加鎖,很容易就會(huì)導(dǎo)致死鎖的情況發(fā)生。這是絕大多數(shù)GUI系統(tǒng)存在的問(wèn)題,所以絕大多數(shù)GUI系統(tǒng)都是采用事件分發(fā)機(jī)制來(lái)實(shí)現(xiàn)的。所以說(shuō)Android為什么設(shè)計(jì)成單線程模型了。

參考博客: Android消息機(jī)制探索(Handler,Looper,Message,MessageQueue)


public static void main(String[] args) {
    ...
    
    //為主線程準(zhǔn)備一個(gè)loop
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        ...
        
        //開(kāi)啟消息循環(huán)。
        Looper.loop();
    
    
    ...
}

prepareMainLooper方法主要是準(zhǔn)備Lopper,里面還掉用了 prepare(false);方法,注意一下參數(shù),傳的是false,也就是不允許主線程的loop推出;如果我們?cè)谧约簞?chuàng)建的線程去創(chuàng)建looper的以后,我們這里傳的就是true了。

  public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
    
    //我們自己創(chuàng)建的線程準(zhǔn)備looper的時(shí)候,會(huì)調(diào)用這個(gè)方法,可以看到傳了false。
     public static void prepare() {
        prepare(true);
    }

接下來(lái)我們分析一下loop()方法。looper方法是一個(gè)無(wú)限循環(huán)的方法,不斷去消息隊(duì)列里取出消息發(fā)送給對(duì)一個(gè)的Handler處理。

public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        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();

        for (;;) {
        //取出一個(gè)消息處理,
            Message msg = queue.next(); // might block
            if (msg == null) {
            //沒(méi)有消息了就退出消息循環(huán)。
                // No message indicates that the message queue is quitting.
                return;
            }

            //把消息分發(fā)給對(duì)應(yīng)的handler處理。
            msg.target.dispatchMessage(msg);

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            //把已經(jīng)處理的消息放回到消息池里面,用來(lái)復(fù)用這個(gè)消息。這個(gè)消息吃的最大緩存熟是50。
            msg.recycleUnchecked();
        }
    }

那么消息隊(duì)列是在什么時(shí)候創(chuàng)建的呢?其實(shí)是在為每個(gè)線程準(zhǔn)備Lopper的時(shí)候創(chuàng)建的,是在Looper的構(gòu)造函數(shù)里

 private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

從上面的邏輯我們可以看出,每個(gè)Looper的創(chuàng)建都會(huì)伴隨著一個(gè)消息隊(duì)列的產(chǎn)生,也就是不同線程之間的消息隊(duì)列是不一樣的,每個(gè)線程都會(huì)創(chuàng)建一個(gè)消息隊(duì)列。另外looper里面的一個(gè)成員sThreadLocal,這個(gè)是ThreadLocal類型的,ThreadLocal這個(gè)類會(huì)單獨(dú)為每個(gè)線程存儲(chǔ)一個(gè)本線程單獨(dú)使用的Looper,線程之間不會(huì)共享,也不會(huì)相互干擾。

  • 消息循環(huán)我們就分析完了,接下來(lái)我們分析消息是怎么分發(fā)到消息隊(duì)列里的
  1. 消息的分發(fā)是通過(guò)下面這樣的方式發(fā)送出去的。
 Handler mHandler = new Handler(Looper.getMainLooper());
 Message msg = Message.obtain()
 給消息中添加參數(shù)的標(biāo)識(shí)。
 msg.what = 1;//這個(gè)消息的標(biāo)識(shí)
 msg.ars1 = 2;//這個(gè)消息鎖攜帶的數(shù)據(jù)
 mHandler.sendMessage(msg) //發(fā)送消息

可以看出,發(fā)送消息需要一個(gè)消息載體Message和運(yùn)送載體的Handler

  • 我們來(lái)分析一下Handler的構(gòu)造函數(shù)
 public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
        //這里為我們自定義Handler給出來(lái)知道方針,不推薦匿名內(nèi)部類,成員類局部累;如果非要在一個(gè)類的內(nèi)部使用,最好就是靜態(tài)的內(nèi)部類。
            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());
            }
        }

  //這個(gè)地方拋出的異常我們應(yīng)該很熟悉類,就是在我們自己創(chuàng)建的子線程里面用消息機(jī)制的時(shí)候沒(méi)有調(diào)用Looper.prepare()發(fā)導(dǎo)致的
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        //拿到當(dāng)前l(fā)oop擁有的handler
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
   public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

  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);
    }
  private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        //為該message指定處理這個(gè)消息的handler,后面在處理這個(gè)消息的時(shí)候
        //就是在循環(huán)中拿到這個(gè)handler去處理這個(gè)消息,所以這一步很重要。
        msg.target = this;
        //由于我們分析的是無(wú)參數(shù)的構(gòu)造mAsynchronous=false
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        //消息入隊(duì)列
        return queue.enqueueMessage(msg, uptimeMillis);
    }

enqueueMessage有兩個(gè)操作,一個(gè)是沒(méi)有隊(duì)列的時(shí)候構(gòu)造隊(duì)列的頭,另外一個(gè)就是入隊(duì)操作。

boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
            if (mQuitting) {
                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;
            }

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                //沒(méi)有隊(duì)列,創(chuàng)建隊(duì)列的頭
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                // 根據(jù)msg.when的先后,找到合適的插入位置,先執(zhí)行的在隊(duì)列前面;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                //隊(duì)列存在,入隊(duì)操作,其實(shí)就是單鏈表的插入操作。
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

消息的入隊(duì)操作介紹完來(lái),下面介紹消息是什么時(shí)候分發(fā)給處理者的
還記得我們的消息的哪個(gè)無(wú)限的for循環(huán)嗎,我再貼一下代碼

   for (;;) {
        //取出一個(gè)消息處理,
            Message msg = queue.next(); // might block
            if (msg == null) {
            //沒(méi)有消息了就推出消息循環(huán)。
                // No message indicates that the message queue is quitting.
                return;
            }

            //把消息分發(fā)給對(duì)應(yīng)的handler處理。
            msg.target.dispatchMessage(msg);

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            //把已經(jīng)處理的消息放回到消息池里面,用來(lái)復(fù)用這個(gè)消息。這個(gè)消息吃的最大緩存熟是50。
            msg.recycleUnchecked();
        }

msg.target.dispatchMessage(msg);這一行就是去把消息分發(fā)給對(duì)應(yīng)的handler處理

   public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

dispatchMessage分發(fā)最終把消息傳給來(lái)handlerMessage分發(fā),所以我們?cè)趧?chuàng)建Handler的時(shí)候都要復(fù)寫handlerMessage方法來(lái)處理分發(fā)過(guò)來(lái)的消息;因?yàn)槲覀冇玫氖菬o(wú)參數(shù)的
Handler的構(gòu)造分發(fā),所以mCallback是null,但是如果我們傳來(lái)mCallback,可以看到回調(diào)函數(shù)的優(yōu)先級(jí)是比handlerMessage分發(fā)的優(yōu)先級(jí)高的。


Android的消息機(jī)制我們就介紹完來(lái),下面我們總結(jié)一下:

  1. 涉及到的類有:
  • Looper:主要用來(lái)創(chuàng)建消息隊(duì)列和對(duì)消息隊(duì)列進(jìn)行遍歷
  • MessageQueue:主要用來(lái)存儲(chǔ)Handler發(fā)過(guò)來(lái)的消息
  • Message:消息的載體,主要負(fù)責(zé)攜帶我們發(fā)送的數(shù)據(jù)
  • Handler:消息的發(fā)送者和執(zhí)行者。
  1. Android中為什么主線程不會(huì)因?yàn)長(zhǎng)ooper.loop()里的死循環(huán)卡死?
  2. 下面是Android中的消息機(jī)制在的處理流程圖
    Android消息機(jī)制.png
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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