Android:非同步訊息源碼解析

來源:互聯網
上載者:User

標籤:android   非同步訊息   源碼解析   

關於非同步訊息的用法,可以看之前的一篇文章http://blog.csdn.net/leelit/article/details/45196827,現在來解析一下源碼。

經典用法
class LooperThread extends Thread {      public Handler mHandler;      public void run() {          Looper.prepare();          mHandler = new Handler() {              public void handleMessage(Message msg) {                  // process incoming messages here              }          };          Looper.loop();      }  }

如此一來,我們便可以在其他線程,通過handler來發送訊息給當前線程,達到非同步效果。

流程

1、Looper.prepare();
這個方法輾轉調用了下列的方法:

    public static void prepare() {        prepare(true);    }    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));    }

prepare方法給ThreadLocal對象set了一個Looper對象,由拋出的異常可以看出每個線程只能有一個Looper對象,那麼這個Looper又是用來幹嘛的呢?

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

Looper綁定了當前線程和MessageQueue。

2、mHandler = new Handler() {...};
執行個體化了Handler對象,後面再回來分析這個Handler對象的作用

3、Looper.loop();

    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 (;;) {            Message msg = queue.next(); // might block            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);            }            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.recycleUnchecked();        }    }

第2、6行可以看到,這個方法擷取了Looper對象和主要的MessageQueue對象,重點看13、14行,方法內部是一個死迴圈,不斷從MessageQueue裡面拉取Message,並且是阻塞式的,也就是說拉不到Message就停在那裡了。假設拉到了Message,則調用第27行

msg.target.dispatchMessage(msg);

很明顯,就是將訊息分發給處理者。而這裡的msg.target正是Handler對象。

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

我們來分別看下這三個可能,也都是常用情景:
①handler對象post一個任務

        handler.post(new Runnable() {            @Override            public void run() {            }        });

繼續調用

    public final boolean post(Runnable r) {       return  sendMessageDelayed(getPostMessage(r), 0);    }    private static Message getPostMessage(Runnable r) {        Message m = Message.obtain();        m.callback = r;        return m;    }

可以看到handler post進去的任務會賦給message後才進行MessageQueue入隊,最終Handler處理這個Message時就會調用這個任務。

②執行個體化Handler對象時傳進一個Callback對象

Handler handler = new Handler(new Handler.Callback() {            @Override            public boolean handleMessage(Message msg) {                return false;            }        });
if (mCallback != null) {                if (mCallback.handleMessage(msg)) {                    return;                }            }

最終就會回調這個handleMessage方法。

③最常見的情景,執行個體化時重寫handleMessage(msg)方法,這也是上面訊息分發的最後一種可能。

最後兩個小問題,
1、Message的MessageQueue入隊操作是由Handler對象進行,入隊時就會把target設為當前操作的Handler,這樣處理訊息時就能找到合適的Handler了!
2、主線程的Looper是由系統產生的,找了半天源碼沒找見,但是官方文檔說的很清楚The main looper for your application is created by the Android environment

小結

Handler對象負責將Message傳入MessageQueue,而MessageQueue由Looper對象產生;
Looper對象負責建立MessageQueue對象,並且不斷從MessageQueue取出Message,一旦取出則分發訊息,最終都會直接或間接被Handler處理。

研究AsyncTask源碼可以發現,內部是對Handler的封裝;
實現子線程發送訊息給主線程很常見,試下向子線程發送訊息,會更加明了。

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

Android:非同步訊息源碼解析

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.