android 消息循環的源碼分析

簡要分析android中消息循環涉及到的幾個方法的源代碼(API19):

1 Handler構造方法

public Handler(Callback callback, boolean async)

{       

         //檢測Handler是否寫成匿名內部類的形式,是則提示這有可能導致內存泄露

         //如果Handler寫成匿名內部類,當我們要銷燬它的外部類對象(通常爲Activity)時

         //該外部類所處的線程中的messageQueue中的message持有handler,也就是匿名內部類對象本身的引用

         //而匿名內部類持有外部類的引用

         //如果messageQueue中有延遲時間很長的message,就會導致handler無法被銷燬,進而導致外部類(Activity等)無法被銷燬

         //造成這個問題的本質原因是handler、looper、messageQueue是threadLocal設置的線程級變量

         //其生命週期可能長於該線程中運行的Activity等外部類,而handler又被寫成了內部類

         //導致內部類的生命週期長於外部類,阻止了外部類的銷燬

        if (FIND_POTENTIAL_LEAKS){

            final Class<? extendsHandler> klass = getClass();

            if((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass())&&

                    (klass.getModifiers() &Modifier.STATIC) == 0) {

                Log.w(TAG, "Thefollowing Handler class should be static or leaks might occur: " +

                    klass.getCanonicalName());

            }

        }

    

     //取得當前線程的looper

    mLooper = Looper.myLooper();

 

     //當前線程沒有looper則報錯

        if (mLooper == null) {

            throw newRuntimeException(

                "Can't create handlerinside thread that has not called Looper.prepare()");

        }

          //從當前線程的looper中取得MessageQueue的引用

        mQueue = mLooper.mQueue;

        mCallback = callback;

        mAsynchronous = async;

         //handler建立的時候就建立和取得了本線程的looper和messagequeue

}

2 Looper的myLooper()方法

 

public static Looper myLooper() {

         //從當前looper的threadLocal線程本地變量中取出本線程擁有的looper

        return sThreadLocal.get();

}

3 Looper的構造方法

//looper對象持有一個threadLocal對象,messageQueue

staticfinal ThreadLocal<Looper> sThreadLocal = newThreadLocal<Looper>();

private staticLooper sMainLooper;

finalMessageQueue mQueue;

finalThread mThread;

//Looper的構造方法是私有的,並且在構造的時候生成了MessageQueue

private Looper(boolean quitAllowed) {

        mQueue = new MessageQueue(quitAllowed);

        mThread = Thread.currentThread();

}    

4 Looper的prepare()方法

//用該方法調用looper的構造方法創建looper

private static void prepare(boolean quitAllowed) {

        if (sThreadLocal.get()!= null) {

            throw newRuntimeException("Only one Looper may be created per thread");

        }

         //創建新的looper對象存入當前looperthreadLocal線程本地變量

        sThreadLocal.set(new Looper(quitAllowed));

         //使用threadLocal對象存儲looper保證了一個線程只有一個looper

         //又因爲message Queue是在looper的構造方法中建立的一個looper只有一個messageQueue

         //這樣線程、loopermessageQueue實現了一一對應

         //但是handler與上述三個部件不是一一對應的一個線程的loopermessageQueue可以對應多個handler

}

5 Looper的loop()方法

//用該方法取得當前線程的looper並啓動其消息循環

public static void loop() {

         //取得當前線程的looper

        final Looper me = myLooper();

        if (me == null) {

            throw newRuntimeException("No Looper; Looper.prepare() wasn't called on thisthread.");

        }                  

         //取得當前線程的MessageQueue

        final MessageQueue queue = me.mQueue;

 

        // Make sure the identity of thisthread is that of the local process,

        // and keep track of what that identitytoken actually is.

        Binder.clearCallingIdentity();

        final long ident =Binder.clearCallingIdentity();

        

         //開啓一個死循環,從messageQueue中取出下一條消息,取出的動作可能是阻塞的

        for (;;){

            Message msg = queue.next(); // might block

            if (msg == null) {

                // No message indicates thatthe message queue is quitting.

                return;

            }

 

            // This must be in a localvariable, in case a UI event sets the logger

            Printer logging = me.mLogging;

            if (logging != null){

               logging.println(">>>>> Dispatching to " +msg.target + " " +

                        msg.callback + ": " +msg.what);

            }

                   

             //將從messageQueue中取得的消息發送給該消息指定的handler去處理

            msg.target.dispatchMessage(msg);

 

            if (logging != null){

               logging.println("<<<<< Finished to " +msg.target + " " + msg.callback);

            }

 

            // Make sure that during the courseof dispatching the

            // identity of the thread wasn'tcorrupted.

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

            }

             

           //handler處理完消息後將其回收

            msg.recycle();

        }

    }

 6 MessageQueue的的next()方法

//messageQueue中取出下一個消息

Message next() {

              ......................

                      

              //在取消息時用同步鎖鎖住messageQueue,防止不同線程的 handler同時操作messageQueue

            synchronized (this) {

                // Try to retrieve the nextmessage.  Return if found.

                final long now =SystemClock.uptimeMillis();

                Message prevMsg = null;

                Message msg = mMessages;

                 

                //從前向後遍歷鏈表,找到第一個異步(其它線程發來的)消息

               if (msg != null && msg.target == null) {

                    // Stalled by abarrier.  Find the next asynchronousmessage in the queue.

                    do {

                        prevMsg = msg;

                        msg = msg.next;

                    } while (msg != null &&!msg.isAsynchronous());

                }

                //由於messageQueueenqueueMessage()方法在將message插入消息鏈表的時候根據消息的執行時間進行了排序

                //所以之前找到的第一個異步消息一定是執行時間最早的異步消息

                if (msg!= null) {

                      //如果當前時間早於執行時間最早的異步消息的執行時間,不執行

                   if (now < msg.when) {

                        // Next message is notready.  Set a timeout to wake up when itis ready.

                        nextPollTimeoutMillis =(int) Math.min(msg.when - now, Integer.MAX_VALUE);

                     //如果當前時間晚於執行時間最早的異步消息的執行時間,返回這個異步消息給looper

                   } else {

                        // Got a message.

                        mBlocked = false;

                        if (prevMsg != null){

                            prevMsg.next =msg.next;

                        } else {

                            mMessages =msg.next;

                        }

                        msg.next = null;

                        if (false)Log.v("MessageQueue", "Returning message: " + msg);

                        msg.markInUse();

                        return msg;

                    }

                } else {

                    // No more messages.

                    nextPollTimeoutMillis = -1;

                }

                  ................................

    }

7 MessageQueue的enqueueMessage()方法

boolean enqueueMessage(Message msg, long when) {

        if (msg.isInUse()) {

            throw newAndroidRuntimeException(msg + " This message is already in use.");

        }

        if (msg.target == null) {

            throw newAndroidRuntimeException("Message must have a target.");

        }

 

        synchronized (this) {

            if (mQuitting) {

                RuntimeException e = newRuntimeException(

                        msg.target + " sending messageto a Handler on a dead thread");

                Log.w("MessageQueue",e.getMessage(), e);

                return false;

            }

 

            msg.when = when;

            Message p = mMessages;

            boolean needWake;

              //按照message自帶的執行時間將message插入到消息鏈表中,執行時間早的插入到靠前的位置

            if (p ==null || when == 0 || when < p.when) {

                // New head, wake up the eventqueue if blocked.

                msg.next = p;

                mMessages = msg;

                needWake = mBlocked;

            } else {

                // Inserted within the middleof the queue.  Usually we don't have towake

                // up the event queue unlessthere is a barrier at the head of the queue

                // and the message is theearliest asynchronous message in the queue.

                needWake = mBlocked &&p.target == null&& msg.isAsynchronous();

                Message prev;

                for (;;) {

                    //向後遍歷消息鏈表

                    prev = p;

                    p = p.next;

                    if (p == null|| when < p.when) {

                        break;

                    }

                    if (needWake&& p.isAsynchronous()) {

                        needWake = false;

                    }

                }

                //將入隊的消息插入到消息鏈表中合適的位置

                msg.next = p; // invariant: p == prev.next

                prev.next = msg;

            }

 

            // We can assume mPtr != 0 becausemQuitting is false.

            if (needWake) {

                nativeWake(mPtr);

            }

        }

        return true;

    }

8  Handler的dispatchMessage()方法

//looper調用handler的此方法messageQueue中取出的message傳給此方法

//此方法按優先級依次查找三種方法來處理message,找到就結束找不到再去找下一個優先級的方法

//優先級1:message自己指定的處理方法

//優先級2:handler在構造時傳入的Handler.Callback接口的實現對象所重寫的handleMessage()方法

//優先級3:handler被覆蓋的handleMessage()方法

public void dispatchMessage(Message msg) {

        if (msg.callback != null){

            handleCallback(msg);

        } else {

            if (mCallback != null){

                if (mCallback.handleMessage(msg)) {

                    return;

                }

            }

            handleMessage(msg);

        }

}    

------------------------------------------------------我是分割線-----------------------------------------------------------------------------

看過了上面幾個跟消息循環有關的方法,我們可以總結一下一個消息從生到死的全過程啦:

消息循環流程:

0. Looper類中有一個靜態成員變量threadLocal對象

1. Looper.prepare():

     (Looper類的靜態方法)

     構造looper對象,looper對象在構造時構造messageQueue對象,

     用Looper類的靜態threadLocal對象將構造出來的looper對象設定爲線程級變量

2. Handler handler = new Handler(){   @Override public void handleMessage(Messagemsg){.........}}  

     構造Handler繼承類的對象,重寫其handleMessage()方法

     構造時調用Looper類的靜態方法myLooper()從Looper類的靜態threadLocal對象中取得當前線程所擁有的looper對象

     此時handler擁有了當前線程的looper和messageQueue對象

3. Looper.loop()

     (Looper類的靜態方法)

     調用Looper類的靜態方法myLooper()從Looper類的靜態threadLocal對象中取得當前線程所擁有的looper對象,

     開啓死循環不停地調用messageQueue的next()方法以阻塞方式從剛纔取得的looper對象中包含的messageQueue中獲取下一個message

     將獲取的message傳給message的target所指定的handler的dispatchMessage()方法

     後者依據優先級調用Handler.Callback或者handler類方法的handleMessage()來處理消息

4. handler.sendMessage(Message msg):

     將傳入message的target設定成自己

     調用當前線程的messageQueue的enqueueMessage()方法將傳入的message按照message執行時間先後順序插入messageQueue

5. 第3步和第4步同時進行

     handler.sendMessage(Messagemsg)通過調用messageQueue的enqueueMessage()將消息加入消息隊列

     Looper.loop()通過messageQueue的next()方法將消息從消息隊列中取出,發給其指定的handler的handleMessage()方法處理

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章