android 消息循环机制--looper handler
Looper類(lèi)說(shuō)明
? Looper?類(lèi)用來(lái)為一個(gè)線(xiàn)程跑一個(gè)消息循環(huán)。
線(xiàn)程在默認(rèn)情況下是沒(méi)有消息循環(huán)與之關(guān)聯(lián)的,Thread類(lèi)在run()方法中的內(nèi)容執(zhí)行完之后就退出了,即線(xiàn)程做完自己的工作之后就結(jié)束了,沒(méi)有循環(huán)的概念。
調(diào)用Looper類(lèi)的?prepare()?方法可以為當(dāng)前線(xiàn)程創(chuàng)建一個(gè)消息循環(huán),調(diào)用loop()?方法使之處理信息,直到循環(huán)結(jié)束。
大多數(shù)和消息循環(huán)的交互是通過(guò)?Handler?類(lèi)進(jìn)行的。
?
下面是一個(gè)典型的實(shí)現(xiàn):
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類(lèi)說(shuō)明
Handler類(lèi)用來(lái)發(fā)送和處理消息(Message)以及和線(xiàn)程的消息隊(duì)列(MessageQueue)關(guān)聯(lián)的Runnable對(duì)象。
每一個(gè)Handler對(duì)象都僅和一個(gè)線(xiàn)程及這個(gè)線(xiàn)程的消息隊(duì)列關(guān)聯(lián)。
一個(gè)特定線(xiàn)程的所有Handler對(duì)象都會(huì)收到同樣的方法。(這是一個(gè)“一對(duì)多”的關(guān)系)。
?
當(dāng)你創(chuàng)建一個(gè)新的Handler對(duì)象,它會(huì)和創(chuàng)建它的這個(gè)線(xiàn)程/線(xiàn)程的消息隊(duì)列綁定,從那個(gè)時(shí)刻開(kāi)始,它將向這個(gè)消息隊(duì)列傳遞消息和runnable對(duì)象,并且當(dāng)它們從隊(duì)列中出來(lái)時(shí)執(zhí)行它們。
Handler主要有兩種用途:
1.合理調(diào)度安排消息和runnable對(duì)象,使它們?cè)趯?lái)的某個(gè)點(diǎn)被執(zhí)行。
2.將一個(gè)動(dòng)作入隊(duì)安排在非當(dāng)前線(xiàn)程執(zhí)行。
?
調(diào)度消息是通過(guò)一系列的post方法和sendMessage方法。
post方法允許你向消息隊(duì)列中入隊(duì)一些Runnable對(duì)象,在它們被接收到的時(shí)候會(huì)被調(diào)用,(實(shí)際上post方法也就是將runnable對(duì)象包裝在消息里,然后再通過(guò)sendMessage方法實(shí)現(xiàn)),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方法允許你入隊(duì)一個(gè)消息對(duì)象(Message),包含一個(gè)bundle數(shù)據(jù),之后將會(huì)被Handler的handleMessage(Message)方法所處理。
(這個(gè)需要你實(shí)現(xiàn)一個(gè)Handler的子類(lèi))。
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)
?
一個(gè)線(xiàn)程對(duì)應(yīng)一個(gè)Looper,有一個(gè)消息隊(duì)列,但是可以關(guān)聯(lián)多個(gè)Handlers。
?
UI線(xiàn)程和非UI線(xiàn)程的通信
當(dāng)你的應(yīng)用進(jìn)程被創(chuàng)建的時(shí)候,應(yīng)用進(jìn)程的主線(xiàn)程(main thread)就建立一個(gè)消息隊(duì)列,操縱top級(jí)別的應(yīng)用對(duì)象(四大compotents比如activities、broadcast receivers等)和它們創(chuàng)建的任何窗口。
???????? 這個(gè)主線(xiàn)程負(fù)責(zé)向UI組件分發(fā)事件(包括繪制事件),也是在這個(gè)主線(xiàn)程里,你的應(yīng)用和Android的UI組件(components from the Android UI toolkit (components from the android.widget and android.view packages))發(fā)生交互。
因?yàn)樾实目紤],所有的View和Widget的操作不是線(xiàn)程安全的,所以相關(guān)操作強(qiáng)制放在同一個(gè)線(xiàn)程,這樣就可以避免多線(xiàn)程帶來(lái)的問(wèn)題。這個(gè)線(xiàn)程就是主線(xiàn)程,也即UI線(xiàn)程。
?
你可以創(chuàng)建自己的線(xiàn)程,通過(guò)一個(gè)Handler對(duì)象和應(yīng)用的主線(xiàn)程通信。
如果你將一個(gè)Handler和你的UI線(xiàn)程連接,處理消息的代碼就將會(huì)在UI線(xiàn)程中執(zhí)行。
新線(xiàn)程和UI線(xiàn)程的通信是通過(guò)從你的新線(xiàn)程調(diào)用和主線(xiàn)程相關(guān)的Handler對(duì)象的post或者sendMessage方法實(shí)現(xiàn)的,給定的Runnable或Message將會(huì)在Handler的消息隊(duì)列中,并且在合適的時(shí)間被處理。
總的來(lái)說(shuō),共有5種方式從非UI線(xiàn)程和UI線(xiàn)程通信:
- Activity.runOnUiThread(Runnable)
- View.post(Runnable)
- View.postDelayed(Runnable, long)
還有就是通過(guò)Handler,或者使用AsyncTask。
具體參見(jiàn)之前的博文:http://www.cnblogs.com/mengdd/p/3418780.html
?
消息循環(huán)
消息處理機(jī)制中,消息存放在一個(gè)消息隊(duì)列中,而線(xiàn)程圍繞這個(gè)隊(duì)列進(jìn)入一個(gè)無(wú)限循環(huán),直到程序退出。
如果隊(duì)列中有消息,線(xiàn)程就會(huì)把消息取出來(lái),并分發(fā)給相應(yīng)的Handler進(jìn)行處理;
如果隊(duì)列中沒(méi)有消息,線(xiàn)程就會(huì)進(jìn)入空閑等待狀態(tài),等待下一個(gè)消息的到來(lái)。
?
Android的主線(xiàn)程循環(huán)創(chuàng)建
Android程序的運(yùn)行入口點(diǎn)可以認(rèn)為是android.app.ActivityThread類(lèi)的main()方法(源碼2.3.3):
public static final void main(String[] args) {// other codes...// 創(chuàng)建主線(xiàn)程循環(huán) Looper.prepareMainLooper();if (sMainThreadHandler == null) {sMainThreadHandler = new Handler();}ActivityThread thread = new ActivityThread();thread.attach(false);// other codes...// 進(jìn)入當(dāng)前線(xiàn)程(此時(shí)是主線(xiàn)程)消息循環(huán) Looper.loop();// other codes... thread.detach();// other codes...}?
這個(gè)main()方法里面為程序創(chuàng)建了主線(xiàn)程循環(huán)。
Looper類(lèi)中的主線(xiàn)程創(chuàng)建方法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...}上面這個(gè)方法是專(zhuān)門(mén)為創(chuàng)建應(yīng)用程序的主線(xiàn)程調(diào)用的,其他線(xiàn)程都不應(yīng)該調(diào)用這個(gè)方法,而應(yīng)該調(diào)用prepare()方法。
主線(xiàn)程的Looper對(duì)象創(chuàng)建好之后會(huì)存在Looper類(lèi)的成員變量mMainLooper里,通過(guò)一個(gè)get方法可以獲取到:
/*** Returns the application's main looper, which lives in the main thread of* the application.*/public synchronized static final Looper getMainLooper() {return mMainLooper;}?
這樣之后,程序中其他線(xiàn)程就可以獲取主線(xiàn)程的消息循環(huán)對(duì)象,從而和主線(xiàn)程通信。
?
線(xiàn)程創(chuàng)建消息循環(huán):Looper.prepare()
非主線(xiàn)程創(chuàng)建消息循環(huán)時(shí),調(diào)用的是Looper類(lèi)的prepare()方法,其實(shí)創(chuàng)建主線(xiàn)程的方法實(shí)質(zhì)也調(diào)用了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());}?
這個(gè)方法會(huì)調(diào)用Looper類(lèi)的私有構(gòu)造方法,創(chuàng)建Looper類(lèi)對(duì)象。
private Looper() {// 私有構(gòu)造方法,在prepare()方法里面調(diào)用// 創(chuàng)建消息隊(duì)列mQueue = new MessageQueue();mRun = true;// 當(dāng)前線(xiàn)程mThread = Thread.currentThread();}?
?
進(jìn)入消息循環(huán):Looper.loop()
不管是不是主線(xiàn)程,prepare之后需要調(diào)用Looper類(lèi)的loop()方法,可以看作是進(jìn)入消息循環(huán):
/*** Run the message queue in this thread. Be sure to call {@link #quit()} to* end the loop.*/public static final void loop() {// 進(jìn)入當(dāng)前線(xiàn)程的消息循環(huán)Looper me = myLooper();MessageQueue queue = me.mQueue;while (true) {// 從隊(duì)列中取出消息Message msg = queue.next(); // might blockif (msg != null) {if (msg.target == null) {// No target is a magic identifier for the quit message.return;}// other codes...// 分發(fā)消息 msg.target.dispatchMessage(msg);// 消息的target是Handler類(lèi)型的對(duì)象// other codes...// 釋放清理 msg.recycle();}}}?
?
消息分發(fā)和處理——Handler
前面創(chuàng)建了消息循環(huán),并且進(jìn)入了這個(gè)循環(huán),但是消息隊(duì)列中的消息是如何加入和處理的呢?是通過(guò)Handler。
Handler構(gòu)造:
Handler有幾個(gè)構(gòu)造重載,如果構(gòu)造時(shí)不提供Looper類(lèi)對(duì)象參數(shù),會(huì)獲取當(dāng)前線(xiàn)程的Looper對(duì)象,即將當(dāng)前線(xiàn)程的消息循環(huán)作為Handler關(guān)聯(lián)的消息循環(huán)。
前面說(shuō)過(guò),不是所有線(xiàn)程都有一個(gè)消息循環(huán),所以如果當(dāng)前線(xiàn)程沒(méi)有消息循環(huán),而構(gòu)造Handler對(duì)象時(shí)又沒(méi)有指定Looper對(duì)象,則會(huì)拋出一個(gè)運(yùn)行時(shí)異常:
mLooper = Looper.myLooper();if (mLooper == null) {throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");}?
如果沒(méi)有拋出異常,Handler對(duì)象構(gòu)造好之后,它就關(guān)聯(lián)了相應(yīng)的Looper實(shí)例和消息隊(duì)列實(shí)例,即完成綁定。
?
消息發(fā)送:
Handler對(duì)象的post方法和sendMessage方法本質(zhì)上都是發(fā)送消息的方法(post類(lèi)方法實(shí)質(zhì)上是調(diào)用了sendMessage方法)。
所謂發(fā)送消息就是把消息放入消息隊(duì)列中的合適位置,并且把消息的target設(shè)置為本Handler對(duì)象。
(這里將消息加入隊(duì)列,也有一些什么線(xiàn)程喚醒的事兒咱們不深入討論了)。
可以添加,也就相應(yīng)地有一些移除方法。
?
消息處理:
在上面的Looper.loop()方法中,調(diào)用了消息對(duì)象target(即發(fā)送這個(gè)消息的Handler對(duì)象)的dispatchMessage()方法。
/*** Handle system messages here.*/public void dispatchMessage(Message msg) {// 首先,處理Message自己的callback,調(diào)用其run方法if (msg.callback != null) {handleCallback(msg);}else {// 其次,調(diào)用Handler自留的接口對(duì)象// 這個(gè)成員變量聲明時(shí)的注釋如下:/*** 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;}}// 最后,調(diào)用handleMessage方法處理消息,Handler類(lèi)中這個(gè)方法為空,子類(lèi)可以重寫(xiě)這個(gè)方法 handleMessage(msg);}}?
Handler類(lèi)的handleMessage()方法默認(rèn)實(shí)現(xiàn)為空:
/*** Subclasses must implement this to receive messages.*/public void handleMessage(Message msg) {}?
上面的代碼中也解釋了為什么一個(gè)消息隊(duì)列可以關(guān)聯(lián)很多個(gè)Handler對(duì)象,因?yàn)殡m然隊(duì)列只有一個(gè),但是消息的target是當(dāng)時(shí)把它加入的Handler對(duì)象。
所以當(dāng)隊(duì)列中的消息處理的時(shí)候,也會(huì)找到當(dāng)時(shí)送它來(lái)的Handler對(duì)象,調(diào)用其相應(yīng)的dispatchMessage()方法,進(jìn)而調(diào)用其中的handleMessage()方法或者mCallback成員的handleMessage()方法來(lái)進(jìn)行處理。
?
參考資料
Handler:http://developer.android.com/reference/android/os/Handler.html
Looper:http://developer.android.com/reference/android/os/Looper.html
?
比較好的幾個(gè)博文:
Android應(yīng)用程序線(xiàn)程消息循環(huán)模型分析:http://blog.csdn.net/luoshengyang/article/details/6905587
? Android應(yīng)用程序消息處理機(jī)制(Looper、Handler)分析:http://blog.csdn.net/luoshengyang/article/details/6817933
Android的消息隊(duì)列模型: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
?
本博客其他相關(guān)博文:
Android中的UI線(xiàn)程與非UI線(xiàn)程:http://www.cnblogs.com/mengdd/p/3418780.html
?
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專(zhuān)家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的android 消息循环机制--looper handler的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 海尔消费金融介绍
- 下一篇: 各种基本的排序算法在Object-C实现