Looper
類用來爲一個線程跑一個消息循環。html
線程在默認狀況下是沒有消息循環與之關聯的,Thread類在run()方法中的內容執行完以後就退出了,即線程作完本身的工做以後就結束了,沒有循環的概念。java
調用Looper類的 prepare()
方法能夠爲當前線程建立一個消息循環,調用loop()
方法使之處理信息,直到循環結束。android
大多數和消息循環的交互是經過 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類用來發送和處理消息(Message)以及和線程的消息隊列(MessageQueue
)關聯的Runnable對象。app
每個Handler對象都僅和一個線程及這個線程的消息隊列關聯。ide
一個特定線程的全部Handler對象都會收到一樣的方法。(這是一個「一對多」的關係)。oop
當你建立一個新的Handler對象,它會和建立它的這個線程/線程的消息隊列綁定,從那個時刻開始,它將向這個消息隊列傳遞消息和runnable對象,而且當它們從隊列中出來時執行它們。post
Handler主要有兩種用途:ui
1.合理調度安排消息和runnable對象,使它們在未來的某個點被執行。
2.將一個動做入隊安排在非當前線程執行。
調度消息是經過一系列的post方法和sendMessage方法。
post方法容許你向消息隊列中入隊一些Runnable對象,在它們被接收到的時候會被調用,(實際上post方法也就是將runnable對象包裝在消息裏,而後再經過sendMessage方法實現),post方法有:
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。
當你的應用進程被建立的時候,應用進程的主線程(main thread)就創建一個消息隊列,操縱top級別的應用對象(好比activities、broadcast receivers等)和它們建立的任何窗口。
由於效率的考慮,全部的View和Widget都不是線程安全的,因此相關操做強制放在同一個線程,這樣就能夠避免多線程帶來的問題。這個線程就是主線程,也即UI線程。
你能夠建立本身的線程,經過一個Handler對象和應用的主線程通訊。
若是你將一個Handler和你的UI線程鏈接,處理消息的代碼就將會在UI線程中執行。
新線程和UI線程的通訊是經過從你的新線程調用和主線程相關的Handler對象的post或者sendMessage方法實現的,給定的Runnable或Message將會在Handler的消息隊列中,而且在合適的時間被處理。
總的來講,共有5種方式從非UI線程和UI線程通訊:
還有就是經過Handler,或者使用AsyncTask。
具體參見以前的博文:http://www.cnblogs.com/mengdd/p/3418780.html
消息處理機制中,消息存放在一個消息隊列中,而線程圍繞這個隊列進入一個無限循環,直到程序退出。
若是隊列中有消息,線程就會把消息取出來,並分發給相應的Handler進行處理;
若是隊列中沒有消息,線程就會進入空閒等待狀態,等待下一個消息的到來。
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()方法,其實建立主線程的方法實質也調用了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(); }
不論是不是主線程,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有幾個構造重載,若是構造時不提供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()方法來進行處理。
Handler:http://developer.android.com/reference/android/os/Handler.html
Looper:http://developer.android.com/reference/android/os/Looper.html
比較好的幾個博文:
Android應用程序線程消息循環模型分析:http://blog.csdn.net/luoshengyang/article/details/6905587
Android應用程序消息處理機制(Looper、Handler)分析:http://blog.csdn.net/luoshengyang/article/details/6817933
Android的消息隊列模型:http://www.cnblogs.com/ghj1976/archive/2011/05/06/2038469.html
Android中的Handler, Looper, MessageQueue和Thread:http://www.cnblogs.com/xirihanlin/archive/2011/04/11/2012746.html
本博客其餘相關博文:
Android中的UI線程與非UI線程:http://www.cnblogs.com/mengdd/p/3418780.html
說明:本文相關源碼是Android 2.3.3版本的。