Android消息機制之Looper

    android中非常重要的一個消息通信機制handler,可以理解爲是android進程內部的一種消息通信機制,通過消息隊列,提高系統的併發性。

    

   根據上圖,可以看出,handler消息隊列的核心是looper,其實Looper實質是一個“綁定”到某個線程的無限循環,該循環不停的從消息隊列中取出消息,並且分發給該消息對應的target,也就是一個Handler來實際的分發處理該消息。那麼我們先來看一看Looper的真實面目。根據代碼段來分析

public class Looper{

    private static final String TAG ="Looper";

 

    // sThreadLocal.get() will return nullunless 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;

    volatile boolean mRun;

......

}

   首先looper會初始化一個靜態的線程局部變量,那麼這個線程局部變量意欲何爲呢,下面看一些prepare(......)這個方法

public staticvoid prepare() {

        prepare(true);

    }

 

    private static void prepare(booleanquitAllowed) {

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

            throw new RuntimeException("Onlyone Looper may be created per thread");

        }

        sThreadLocal.set(newLooper(quitAllowed));

    }

 

   根據prepare()方法的代碼可以看出,該公共方法會調用Looper類的一個私有的方法prepare(boolean quitAllowed),從這個方法裏,我們應該可以看出sThreadLocal這個線程局部變量的作用了,對了,沒錯,你肯定猜出來啦,就是爲了將一個Looper對象綁定到當前線程中,就是爲了線程的併發訪問,如此簡單而已。那麼類Looper的構造方法做了什麼呢?

   private Looper(boolean quitAllowed) {

        mQueue = new MessageQueue(quitAllowed);

        mRun = true;

        mThread = Thread.currentThread();

    }

   這個方法的主要工作就是生成了一個消息隊列的對象,並且初始化mThread爲當前進程,那麼這個mThread是用來做什麼的呢,這個可以根據Looper類的一個公共成員方法getThread()方法來推測,這個方法應該是用於ThreadLocal這個類的內部來使用,可能是作爲一個key,來存儲Looper對象。

   所以說,當你想在一個線程中綁定一個Looper對象時,肯定要首先調用Looper類的靜態公共方法prepare()。那麼你可能現在會問了,你不是說,會將一個無限循環綁定到當前線程中,彆着急,下面就是了,

public staticvoid loop() {

 ①       final Looper me =myLooper();

        if (me == null) {

            throw new RuntimeException("NoLooper; Looper.prepare() wasn't called on this thread.");

        }

②        final MessageQueuequeue = 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();

 

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

            }

 

        ④   msg.target.dispatchMessage(msg);

 

            if (logging != null) {

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

            }

 

         ......

 

     ⑤       msg.recycle();

        }

    }

   這又是一個類的靜態公共方法,所以對於Looper類來說,當你在某個線程中調用Looper類中的方法時,都是通過類名來調用的,而不是通過Looper的對象來調用,因爲生成Looper對象是由prepare這個公共方法在類的內部來實現的。

   從上面的編號1處的代碼段可以知道,該方法首先會判斷是否可以通過sThreadLocal來獲取當前進程的Looper類對象,如果獲取失敗,則跑出異常,這個異常是說當前進程沒有調用Looper.prepare()方法,從這裏,我們也可以推斷,在一個進程中,prepare方法肯定要在loop()方法之前被調用。

   編號2處的代碼段是獲取消息隊列的對象。

   編號3處的代碼則是進入了一個無限的for循環,這個for循環就是從消息隊列中取出消息,

   編號4則是這個過程的中心環節了,通過獲取msg的target成員變量(也就是一個handler對象),然後通過該變量調用disapatchMessage(msg)來分發處理消息。

   編號5則是用於回收處理過的消息對象。

以上簡單分析了Looper的實現原理,下面一節,將會進一步分析Handler的消息機制。由於個人水平有限,如有錯誤,敬請指正!



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