android中handler和looper的工作原理
在android中,UI執行緒和其他子執行緒之間傳遞資料一般要用到handler和looper,那麼其工作原理是 什麼呢?
我們通用的方法是:在UI執行緒中建立handler--將handler傳遞到子執行緒中--在子執行緒中sendmessage---訊息被載入進looper的message佇列中--在UI執行緒中handlemessage
該方法我們可以用一個比喻:
Handler在某個國家(主looper執行緒)例項化以後,就在該國家建立一個機構,該機構會派遣人員(handler)到某個子執行緒,該人員身上帶著訊息鴿子(obtainmessage),這些訊息鴿子的目的地(target)自動鎖定那個handler機構,當收集到訊息後,將訊息鴿子放出去(sendmessage)
但是,我們能不能在子執行緒中建立handler,實現UI執行緒的修改呢?
當然可以!直接派遣looper到子執行緒,跟那裡的handler繫結(通過handler的構造方法將looper傳進去),把在子執行緒例項化的handler變成主執行緒直屬handler來為自己服務,這樣在子執行緒的handleMessage方法中執行UI執行緒的修改也是不會報錯的。
那麼,到底是什麼機制,使這兩種方法都能行得通?
通過研究android原始碼之 handler.java ~~ Looper.java,我們可以得到以下結論:
handler在哪裡建立是沒有關係的,重要的是handler傳送的message到達了那個looper的訊息佇列,不管通過什麼方法,只要讓handler傳送的訊息到達UI執行緒Looper的訊息佇列,就能實現對UI執行緒的修改!
要理解上面這句話,首先要了解這麼幾個概念:
1,一個普通Thread不能建立handler的,需要在該執行緒的run()方法中執行Looper.papare(),將該執行緒變為looperThread。(UI執行緒自動執行了looper.papare和looper.loop()方法,所以UI執行緒本身就是looper執行緒)
2,一個looperThread只能有一個looper,一個looper繫結一個messageQeue;
3,一個looperThread可以用多個handler;
handler跟Thread沒有關係,它跟looper繫結,具體繫結那個looper,就要看用的那個構造方法,如果用的是new Handler()這個構造方法,會預設繫結它所線上程的looper和訊息佇列(handler.java原始碼中描述為:mLooper = Looper.myLooper();mQeue = mLooper.Qeue),如果用的是new Handler(Looper looper)的構造方法,就會與傳進去的那個looper繫結;
繫結某個looper,當sendMessage時就會向那個looper繫結的訊息佇列(messageQeue)裡傳送訊息。
(那麼handlerMessage()這個方法是在哪裡執行的呢?)
Looper裡有個死迴圈方法loop(),不斷檢查與其繫結的訊息佇列裡的訊息,一條條按順序拿出,並執行msg.target.dispathMessage(msg),這個dispathMessage本身呼叫的就是handleMessage()方法,所以,handlerMessage本質上是在Looper的死迴圈裡處理的,只要這個Looper屬於UI執行緒,那麼程式就不會報錯,可以順利執行。
====================================================================================================================================
上面描述的是子執行緒操作UI時報錯的解決辦法,那麼子執行緒操作UI就一定會報錯崩潰嗎?
不!首先我們要了解系統為什麼會崩毀並報錯,是系統本身有一個判斷機制,當執行到layoutRequset 時,只有判斷到parentLayout != null系統才會判斷並丟擲異常,導致錯誤;
其實,在oncreate()方法中執行對UI控制元件值的修改是可以的,因為此時activity的生命週期才剛開始,parentLayout還沒建立和繪製,其值是null,所以“監控失效”,所以不會拋錯和崩潰,並且控制元件的屬性值會被正常修改。