Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> 深入理解Android異步消息處理機制,

深入理解Android異步消息處理機制,

編輯:關於android開發

深入理解Android異步消息處理機制,


一。概述

 

  Android 中的異步消息處理主要分為四個部分組成,Message、Hndler、MessageQueue 和 Looper。其關系如下圖所示:

 

  1. Message 是線程之間傳遞的消息,它可以在內部攜帶少量信息,用於在不同線程之間交換數據。

  2. MessageQueue 是消息隊列,它主要用於存放所有由 Handler 發送過來的消息,這部分消息會一直在消息隊列中,等待被處理。每個線程中只會有一個 MessageQueue 對象。

  3. Handler 是處理者,它主要用於發送和處理消息。 發送消息一般使用 handler  的 sendMessage()方法,處理消息會調用 handleMessage() 方法。

  4. Looper 是每個線程中 MessageQueue 的管家, 調用 loop() 方法後,就會進入到一個無限循環當中,然後每當發現 MessageQueue 中存在一條消息,就會將其取出,並傳遞到 handleMessage

()方法當中。每個線程中也只會有一個Looper對象。

 

二。詳細介紹

1、Looper

  對於Looper主要是prepare()和loop()兩個方法。

  

public static final void prepare() {  
        if (sThreadLocal.get() != null) {  
            throw new RuntimeException("Only one Looper may be created per thread");  
        }  
        sThreadLocal.set(new Looper(true));  
}  

  sThreadLocal是一個ThreadLocal對象,可以在一個線程中存儲變量。Looper 就是存儲在sThreadLocal裡面。這個方法被調用後,首先會判斷當前線程裡面有沒有 Looper對象,如果沒有就會創建一  

個  Looper 對象,如果存在則會拋出異常。可見,prepare()方法,不能被調用兩次。這就保證了一個線程只有一個Looper對象。

  接下來我們看一下Looper的構造函數:

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

  在 Looper 的構造函數中,創建了 MessageQueue 對象,這也保證了一個線程只有一個 MessageQueue 對象。

 

  然後我們看看 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.recycle();
        }
}

  這個方法先調用 myLooper() 方法,得到 sThreadLocal 中保存的 Looper 對象,並得到 looper 對象對應的 MessageQueue 對象,然後就進入無限循環。

  該循環主要包括:取出一條消息,如果沒有消息則阻塞; 調用  msg.target.dispatchMessage(msg);把消息交給msg的target的dispatchMessage方法去處理。

  Looper主要作用:

  1、 與當前線程綁定,保證一個線程只會有一個Looper實例,同時一個Looper實例也只有一個MessageQueue。
  

  2、 loop()方法,不斷從MessageQueue中去取消息,交給消息的target屬性的dispatchMessage去處理。

 

2、Handler

  在使用Handler之前,我們都是初始化一個實例,比如用於更新UI線程,我們會在聲明的時候直接初始化,或者在onCreate中初始化Handler實例。

private Handler mHandler = new Handler()
    {
        public void handleMessage(android.os.Message msg)
        {
            switch (msg.what)
            {
            case value:
                
                break;

            default:
                break;
            }
        };
    };

  

 

三。小結

 

  1、首先Looper.prepare()在本線程中保存一個Looper實例,然後該實例中保存一個MessageQueue對象;因為Looper.prepare()在一個線程中只能調用一次,所以MessageQueue在一個線程中只會

存在一個。大家可能還會問,那麼在Activity中,我們並沒有顯示的調用Looper.prepare()和Looper.loop()方法,為啥Handler可以成功創建呢,這是因為在Activity的啟動代碼中,已經在當前UI線程調用

了Looper.prepare()和Looper.loop()方法

  2、Looper.loop()會讓當前線程進入一個無限循環,不端從MessageQueue的實例中讀取消息,然後回調msg.target.dispatchMessage(msg)方法。

  3、Handler的構造方法,會首先得到當前線程中保存的Looper實例,並與Looper實例中的MessageQueue相關聯。

  4、Handler的sendMessage方法,會給msg的target賦值為handler自身,然後加入MessageQueue中。

  5、在構造Handler實例時,我們會重寫handleMessage方法,也就是msg.target.dispatchMessage(msg)最終調用的方法。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved