Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android的消息循環機制 Looper Handler類分析

Android的消息循環機制 Looper Handler類分析

編輯:關於Android編程

  Looper類說明    Looper 類用來為一個線程跑一個消息循環。     線程在默認情況下是沒有消息循環與之關聯的,Thread類在run()方法中的內容執行完之後就退出了,即線程做完自己的工作之後就結束了,沒有循環的概念。     調用Looper類的 prepare() 方法可以為當前線程創建一個消息循環,調用loop() 方法使之處理信息,直到循環結束。     大多數和消息循環的交互是通過 Handler 類進行的。         下面是一個典型的實現:   復制代碼   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類說明     Handler類用來發送和處理消息(Message)以及和線程的消息隊列(MessageQueue)關聯的Runnable對象。     每一個Handler對象都僅和一個線程及這個線程的消息隊列關聯。     一個特定線程的所有Handler對象都會收到同樣的方法。(這是一個“一對多”的關系)。         當你創建一個新的Handler對象,它會和創建它的這個線程/線程的消息隊列綁定,從那個時刻開始,它將向這個消息隊列傳遞消息和runnable對象,並且當它們從隊列中出來時執行它們。     Handler主要有兩種用途:     1.合理調度安排消息和runnable對象,使它們在將來的某個點被執行。     2.將一個動作入隊安排在非當前線程執行。         調度消息是通過一系列的post方法和sendMessage方法。     post方法允許你向消息隊列中入隊一些Runnable對象,在它們被接收到的時候會被調用,(實際上post方法也就是將runnable對象包裝在消息裡,然後再通過sendMessage方法實現),post方法有:     post(Runnable r)     postAtFrontOfQueue(Runnable r)     postAtTime(Runnable r, Object token, long uptimeMillis)     postAtTime(Runnable r, long uptimeMillis)     postDelayed(Runnable r, long delayMillis)         sendMessage方法允許你入隊一個消息對象(Message),包含一個bundle數據,之後將會被Handler的handleMessage(Message)方法所處理。     (這個需要你實現一個Handler的子類)。     sendMessage方法有:     sendEmptyMessage(int what)     sendEmptyMessageAtTime(int what, long uptimeMillis)     sendEmptyMessageDelayed(int what, long delayMillis)     sendMessage(Message msg)     sendMessageAtFrontOfQueue(Message msg)     sendMessageAtTime(Message msg, long uptimeMillis)     sendMessageDelayed(Message msg, long delayMillis)         一個線程對應一個Looper,有一個消息隊列,但是可以關聯多個Handlers。     UI線程和非UI線程的通信   當你的應用進程被創建的時候,應用進程的主線程(main thread)就建立一個消息隊列,操縱top級別的應用對象(比如activities、broadcast receivers等)和它們創建的任何窗口。     因為效率的考慮,所有的View和Widget都不是線程安全的,所以相關操作強制放在同一個線程,這樣就可以避免多線程帶來的問題。這個線程就是主線程,也即UI線程。         你可以創建自己的線程,通過一個Handler對象和應用的主線程通信。     如果你將一個Handler和你的UI線程連接,處理消息的代碼就將會在UI線程中執行。     新線程和UI線程的通信是通過從你的新線程調用和主線程相關的Handler對象的post或者sendMessage方法實現的,給定的Runnable或Message將會在Handler的消息隊列中,並且在合適的時間被處理。     總的來說,共有5種方式從非UI線程和UI線程通信:   Activity.runOnUiThread(Runnable) View.post(Runnable) View.postDelayed(Runnable, long)   還有就是通過Handler,或者使用AsyncTask。     具體參見之前的博文:http://www.cnblogs.com/mengdd/p/3418780.html       消息循環   消息處理機制中,消息存放在一個消息隊列中,而線程圍繞這個隊列進入一個無限循環,直到程序退出。     如果隊列中有消息,線程就會把消息取出來,並分發給相應的Handler進行處理;     如果隊列中沒有消息,線程就會進入空閒等待狀態,等待下一個消息的到來。       Android的主線程循環創建   Android程序的運行入口點可以認為是android.app.ActivityThread類的main()方法(源碼2.3.3):   復制代碼     public static final void main(String[] args) {         // other codes...           // 創建主線程循環         Looper.prepareMainLooper();         if (sMainThreadHandler == null) {             sMainThreadHandler = new Handler();         }           ActivityThread thread = new ActivityThread();         thread.attach(false);           // other codes...           // 進入當前線程(此時是主線程)消息循環         Looper.loop();           // other codes...           thread.detach();         // other codes...     } 復制代碼       這個main()方法裡面為程序創建了主線程循環。     Looper類中的主線程創建方法prepareMainLooper():   復制代碼     /**      * Initialize the current thread as a looper, marking it as an application's      * main looper. The main looper for your application is created by the      * Android environment, so you should never need to call this function      * yourself. {@link #prepare()}      */       public static final void prepareMainLooper() {         prepare();         setMainLooper(myLooper());         // other codes...     } 復制代碼   上面這個方法是專門為創建應用程序的主線程調用的,其他線程都不應該調用這個方法,而應該調用prepare()方法。     主線程的Looper對象創建好之後會存在Looper類的成員變量mMainLooper裡,通過一個get方法可以獲取到:   復制代碼     /**      * Returns the application's main looper, which lives in the main thread of      * the application.      */     public synchronized static final Looper getMainLooper() {         return mMainLooper;     } 復制代碼       這樣之後,程序中其他線程就可以獲取主線程的消息循環對象,從而和主線程通信。       線程創建消息循環:Looper.prepare()   非主線程創建消息循環時,調用的是Looper類的prepare()方法,其實創建主線程的方法實質也調用了prepare方法:   復制代碼     /**      * Initialize the current thread as a looper. This gives you a chance to      * create handlers that then reference this looper, before actually starting      * the loop. Be sure to call {@link #loop()} after calling this method, and      * end it by calling {@link #quit()}.      */     public static final void prepare() {         if (sThreadLocal.get() != null) {             throw new RuntimeException(                     "Only one Looper may be created per thread");         }         sThreadLocal.set(new Looper());     } 復制代碼       這個方法會調用Looper類的私有構造方法,創建Looper類對象。   復制代碼     private Looper() {         // 私有構造方法,在prepare()方法裡面調用         // 創建消息隊列         mQueue = new MessageQueue();         mRun = true;         // 當前線程         mThread = Thread.currentThread();     } 復制代碼         進入消息循環:Looper.loop()   不管是不是主線程,prepare之後需要調用Looper類的loop()方法,可以看作是進入消息循環:   復制代碼 /**      * Run the message queue in this thread. Be sure to call {@link #quit()} to      * end the loop.      */     public static final void loop() {         // 進入當前線程的消息循環         Looper me = myLooper();         MessageQueue queue = me.mQueue;         while (true) {               // 從隊列中取出消息             Message msg = queue.next(); // might block               if (msg != null) {                 if (msg.target == null) {                     // No target is a magic identifier for the quit message.                     return;                 }                 // other codes...                   // 分發消息                 msg.target.dispatchMessage(msg);                 // 消息的target是Handler類型的對象                   // other codes...                   // 釋放清理                 msg.recycle();             }         }     } 復制代碼         消息分發和處理——Handler   前面創建了消息循環,並且進入了這個循環,但是消息隊列中的消息是如何加入和處理的呢?是通過Handler。   Handler構造:     Handler有幾個構造重載,如果構造時不提供Looper類對象參數,會獲取當前線程的Looper對象,即將當前線程的消息循環作為Handler關聯的消息循環。     前面說過,不是所有線程都有一個消息循環,所以如果當前線程沒有消息循環,而構造Handler對象時又沒有指定Looper對象,則會拋出一個運行時異常:           mLooper = Looper.myLooper();         if (mLooper == null) {             throw new RuntimeException(                 "Can't create handler inside thread that has not called Looper.prepare()");         }       如果沒有拋出異常,Handler對象構造好之後,它就關聯了相應的Looper實例和消息隊列實例,即完成綁定。       消息發送:     Handler對象的post方法和sendMessage方法本質上都是發送消息的方法(post類方法實質上是調用了sendMessage方法)。     所謂發送消息就是把消息放入消息隊列中的合適位置,並且把消息的target設置為本Handler對象。     (這裡將消息加入隊列,也有一些什麼線程喚醒的事兒咱們不深入討論了)。     可以添加,也就相應地有一些移除方法。       消息處理:     在上面的Looper.loop()方法中,調用了消息對象target(即發送這個消息的Handler對象)的dispatchMessage()方法。   復制代碼    /**      * Handle system messages here.      */     public void dispatchMessage(Message msg) {           // 首先,處理Message自己的callback,調用其run方法         if (msg.callback != null) {             handleCallback(msg);         }         else {             // 其次,調用Handler自留的接口對象             // 這個成員變量聲明時的注釋如下:             /**              * Callback interface you can use when instantiating a Handler to              * avoid having to implement your own subclass of Handler.              */             if (mCallback != null) {                 if (mCallback.handleMessage(msg)) {                     return;                 }             }               // 最後,調用handleMessage方法處理消息,Handler類中這個方法為空,子類可以重寫這個方法             handleMessage(msg);         }     } 復制代碼       Handler類的handleMessage()方法默認實現為空:       /**      * Subclasses must implement this to receive messages.      */     public void handleMessage(Message msg) {     }       上面的代碼中也解釋了為什麼一個消息隊列可以關聯很多個Handler對象,因為雖然隊列只有一個,但是消息的target是當時把它加入的Handler對象。     所以當隊列中的消息處理的時候,也會找到當時送它來的Handler對象,調用其相應的dispatchMessage()方法,進而調用其中的handleMessage()方法或者mCallback成員的handleMessage()方法來進行處理。    
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved