Android的Handler,Message,Looper的原理詳解

先說說Looper類:Looper就是爲每個線程建立一個Looper對象,維護一個MessageQueue,並循環從MessageQueue中取出消息並分發給Handler執行。下面是Looper源碼中如何使用的一個示例數組

class LooperThread extends Thread {併發

  *      public Handler mHandler;ide

  *函數

  *      public void run() {oop

  *          Looper.prepare();post

  *ui

  *          mHandler = new Handler() {this

  *              public void handleMessage(Message msg) {spa

  *                  // process incoming messages here線程

  *              }

  *          };

  *

  *          Looper.loop();

  *      }

  *  }

咱們看看Looper.prepare幹了些什麼事

public static void prepare() {

        prepare(true);

    }


    //判斷當前線程是否有Looper對象,沒有則new一個並放到ThreadLocal中

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

    }

至於這個地方爲何要用ThreadLocal來存儲Looper對象呢:

咱們知道ThreadLocal是與線程相關的一個類,系統規定每一個線程只能有一個Looper對象,也就是說只能由一個MessageQueue對象,這樣便於維護消息隊列。若是我已經prepare一次了,那麼個人當前線程中是有Looper對象的,並存儲在當前線程變量內。當你再在此線程prepare時,ThreadLocal對象會獲取當前線程是否有Looper對象,若是有,直接拋異常,這是系統所不容許的,

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

所以ThreadLocal用來存儲Looper對象,設計的真雞賊,不知道你們還有沒有別的方式來控制一個線程只有一個Looper對象。看到不少博客都說ThreadLocal是用來併發控制資源共享的,ThreadLocal存儲每一個線程對資源的副本,再次本人以爲純屬扯淡,你去看看ThreadLocal的例子,若是ThreadLocal存儲副本,你丫的把「主本」給我找出來?經過Looper就能夠看出來ThreadLocal只是存儲當前線程的相關變量。

建立完Looper對象,並初始化了MessageQueue對象,下面該進入不斷循環,取出消息了:

public static void loop() {

        final Looper me = myLooper();//你看,每次都是myLooper獲取當前線程的Looper對象,省得獲取到別的線程的了

        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 (;;) {//死循環吧

            Message msg = queue.next(); // 從隊列中獲取下一個

            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

            Printer logging = me.mLogging;

            if (logging != null) {

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

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

            }


            //獲取到消息以後分發給HAndler處理,其實這個Handler就是target

            msg.target.dispatchMessage(msg);


            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.recycle();//回收Message對象,重複利用就在此,哈哈。。下面會講

        }

    }



至此,Looper的主要工做講完了。

接着是Message,就是攜帶了一些數據,被handler帶着飛。重複利用問題以及鏈表的結構。

先看看都帶了什麼數據:

/*package*/ int flags;


    /*package*/ long when;//時間而已

    

    /*package*/ Bundle data;//數據

    

    /*package*/ Handler target;     //Handler,代表我這個Message要被哪一個Handler處理,固然是誰發送我,誰處理,發送個人時候給我賦值

    

    /*package*/ Runnable callback;  //post(Runnable r)函數使用 

    

    // sometimes we store linked lists of these things

    /*package*/ Message next;//連接下一個Message

再看看重複利用:


public void recycle() {

        clearForRecycle();//把要回收的這個Message數據清空


        synchronized (sPoolSync) {

            if (sPoolSize < MAX_POOL_SIZE) {//不超過50個,源碼的常量

                next = sPool;

                sPool = this;//關鍵在這,又把這個對象賦給了靜態的sPool引用,gc不會回收此Message

                sPoolSize++;

            }

        }

    }

 public static Message obtain() {

        synchronized (sPoolSync) {

            if (sPool != null) {

                Message m = sPool;

                sPool = m.next;

                m.next = null;

                sPoolSize--;

                return m;

            }

        }

        return new Message();

    }



看吧,咱們obtain的時候會利用剛纔回收掉的Message,不然才new Message();

再看MessageQueue,他裏面並不真正的使用數組的形式去存儲一系列的Message,而是經過Message的next使用鏈表的形式維護Message隊列,只要能拿到鏈表的第一個Message就能夠展開一系列的循環讀取Message。經過next()方法獲取。代碼就不貼了。

最後是Handler類介紹:建立一個Handler對象,通常都會重寫handleMesage方法。去處理咱們發送過來的消息,handleMessage什麼時候被調用呢,看下

 public void dispatchMessage(Message msg) {

        if (msg.callback != null) {

            handleCallback(msg);//處理handler.post(Runnable r)的

        } else {

            if (mCallback != null) {

                if (mCallback.handleMessage(msg)) {

                    return;

                }

            }

            handleMessage(msg);//調用了吧

        }

    }

那麼dispatchMessage的調用呢,看前面的Looper.loop(),娶到一個Message以後,經過Message 的target(Handler)調用到的,這樣處理的過程。

再看看Handler的發送:

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

        msg.target = this;//這個很重要就是把此Handler對象直接賦給此Message的target,

        if (mAsynchronous) {

            msg.setAsynchronous(true);

        }

        return queue.enqueueMessage(msg, uptimeMillis);//這個就是把此Message對象加入MessageQueue

    }



這樣,整個流程就走完了,發送到加入隊列,再取,在處理的流程。

發送是Handler,加入隊列是MessageQueue,取是Looper(內部也是MesageQueue取的,不過是有Looper維護此隊列而已),處理是Handler。

Activity主線程,在程序中的main方法已經prepare了,而且loop了,因此咱們不必建立Looper對象。

在咱們本身建立的子線程中,咱們要想處理消息,必須Looper.prepare,而且loop()。

相關文章
相關標籤/搜索