Handler機制分析

一、什么是handler?

handler是Android給我們提供用來更新UI的一套機制,也是一套消息處理機制,我們可以發消息,也可以通過它 處理消息。

二、那為什么要用handler呢?我能不能不用?

肯定是不行的。因為android在設計的時候就封裝了一套消息創建、傳遞、處理。如果不遵循就不能更新UI信息,就會報出異常。

三、Android為什么要設計只能用handler機制更新UI呢?

最根本的目的就是為了解決多線程并發的問題!

? ? ? ? ? ?打個比方,如果在一個activity中有多個線程,并且沒有加鎖,就會出現界面錯亂的問題。但是如果對這些更新UI的操作都加鎖處理,又會導致性能下降。

? ? ? ? ? 處于對性能的問題考慮,Android給我們提供這一套更新UI的機制我們只需要遵循這種機制就行了。不用再去關系多線程的問題,所有的更新UI的操作,都是在主線程的消息隊列中去輪訓的。

四、handler中send和post方法的區別

在Android中handler用來進行進程間通信,其中有send和post兩種方法,大家常用的send方法,其是在工作線程中處理完耗時操作后調用handler的sendMessage(message)把message對象發送給主線程,在主線程中重寫handlerMessage()方法,判斷接收到的消息進行更新UI的操作;而post方法傳遞的是一個runnable對象,更新UI的操作也是在這個runnable的run方法中進行的,也就是說run方法中的代碼是執行在主線程中的,雖然它是寫在工作線程中,主線程在接收到消息后自動執行runnable的run方法中的代碼。

public class MainActivity extends Activity {

??? private Button btSend;

??? private Button btPost;

??? private TextView textview;

??? private static final int SEND_UPDATA_TEXT=0;

??? private Handler handler=new Handler(){

?? ??? ?public void handleMessage(Message msg) {

?? ??? ??? ?switch (msg.what) {

?? ??? ??? ?case SEND_UPDATA_TEXT:

?? ??? ??? ??? ?textview.setText("sendMessage發來的消息");

?? ??? ??? ??? ?break;

?? ??? ??? ?default:

?? ??? ??? ??? ?break;

?? ??? ??? ?}

?? ??? ?};

??? };

?? ?@Override

?? ?protected void onCreate(Bundle savedInstanceState) {

?? ??? ?super.onCreate(savedInstanceState);

?? ??? ?setContentView(R.layout.activity_main);

?? ??? ?//初始化控件

?? ??? ?setViews();

?? ??? ?//事件監聽

?? ??? ?setListener();

?? ?}


?? ?private void setListener() {


?? ??? btSend.setOnClickListener(new OnClickListener() {

?? ??? ?@Override

?? ??? ?public void onClick(View v) {

?? ??? ??? ?new Thread(new Runnable() {

?? ??? ??? ??? ?@Override

?? ??? ??? ??? ?public void run() {

?? ??? ??? ??? ??? ?Message message=new Message();

?? ??? ??? ??? ??? ?message.what=SEND_UPDATA_TEXT;

?? ??? ??? ??? ??? ?handler.sendMessage(message);

?? ??? ??? ??? ?}

?? ??? ??? ?}).start();

?? ??? ?}

?? ?});


?? ??? btPost.setOnClickListener(new OnClickListener() {

?? ??? ?@Override

?? ??? ?public void onClick(View v) {

?? ??? ??? ?new Thread(new Runnable() {

?? ??? ??? ??? ?@Override

?? ??? ??? ??? ?public void run() {

?? ??? ??? ??? ??? ?//使用post發送消息

?? ??? ??? ??? ??? ?handler.post(new Runnable() {

?? ??? ??? ??? ??? ??? ?//run方法中的代碼執行在UI線程中

?? ??? ??? ??? ??? ??? ?@Override

?? ??? ??? ??? ??? ??? ?public void run() {

?? ??? ??? ??? ??? ??? ??? ?textview.setText("post發來消息");

?? ??? ??? ??? ??? ??? ?}

?? ??? ??? ??? ??? ?});

?? ??? ??? ??? ?}

?? ??? ??? ?}).start();

?? ??? ?}

?? ?});

?? ?}

?? ?private void setViews() {

?? ??? ?btSend=(Button) findViewById(R.id.bt_send);

?? ??? ?btPost=(Button) findViewById(R.id.bt_post);

?? ??? ?textview=(TextView) findViewById(R.id.textview);

?? ?}



}

源碼流程分析

handler 發送Message(消息)至MessageQueue(模擬隊列),由Looper(循環器)不斷的循環取出,然后通知handler處理消息,這是整個消息機制


Handler流程圖

Looper 消息輪訓器

MessageQueue消息暫存隊列(單鏈表結構)

Message 消息

Handler 收發消息工具

請解釋下在單線程模型中Message、Handler、Message Queue、Looper之間的關系。

答:簡單的說,Handler獲取當前線程中的looper對象,looper用來從存放Message的MessageQueue中取出Message,再有Handler進行Message的分發和處理.

Message Queue(消息隊列)/8:用來存放通過Handler發布的消息,通常附屬于某一個創建它的線程,可以通過Looper.myQueue()得到當前線程的消息隊列

Handler:可以發布或者處理一個消息或者操作一個Runnable,通過Handler發布消息,消息將只會發送到與它關聯的消息隊列,然也只能處理該消息隊列中的消息

Looper:是Handler和消息隊列之間通訊橋梁,程序組件首先通過Handler把消息傳遞給Looper,Looper把消息放入隊列。Looper也把消息隊列里的消息廣播給所有的

Handler:Handler接受到消息后調用handleMessage進行處理

Message:消息的類型,在Handler類中的handleMessage方法中得到單個的消息進行處理

在單線程模型下,為了線程通信問題,Android設計了一個Message Queue(消息隊列), 線程間可以通過該Message Queue并結合Handler和Looper組件進行信息交換。下面將對它們進行分別介紹:

1)?Message

?Message消息,理解為線程間交流的信息,處理數據后臺線程需要更新UI,則發送Message內含一些數據給UI線程。

2)?Handler

?Handler處理者,是Message的主要處理者,負責Message的發送,Message內容的執行處理。后臺線程就是通過傳進來的 Handler對象引用來sendMessage(Message)。而使用Handler,需要implement 該類的 handleMessage(Message)方法,它是處理這些Message的操作內容,例如Update UI。通常需要子類化Handler來實現handleMessage方法。

3)?Message Queue

?Message Queue消息隊列,用來存放通過Handler發布的消息,按照先進先出執行。

?每個message queue都會有一個對應的Handler。Handler會向message queue通過兩種方法發送消息:sendMessage或post。這兩種消息都會插在message queue隊尾并按先進先出執行。但通過這兩種方法發送的消息執行的方式略有不同:通過sendMessage發送的是一個message對象,會被 Handler的handleMessage()函數處理;而通過post方法發送的是一個runnable對象,則會自己執行。

4)?Looper

?Looper是每條線程里的Message Queue的管家。Android沒有Global的Message Queue,而Android會自動替主線程(UI線程)建立Message Queue,但在子線程里并沒有建立Message Queue。所以調用Looper.getMainLooper()得到的主線程的Looper不為NULL,但調用Looper.myLooper() 得到當前線程的Looper就有可能為NULL。對于子線程使用Looper,API Doc提供了正確的使用方法:這個Message機制的大概流程:

?①在Looper.loop()方法運行開始后,循環地按照接收順序取出Message Queue里面的非NULL的Message。

② 一開始Message Queue里面的Message都是NULL的。當Handler.sendMessage(Message)到Message Queue,該函數里面設置了那個Message對象的target屬性是當前的Handler對象。隨后Looper取出了那個Message,則調用 該Message的target指向的Hander的dispatchMessage函數對Message進行處理。在dispatchMessage方法里,如何處理Message則由用戶指定,三個判斷,優先級從高到低:

a)?Message里面的Callback,一個實現了Runnable接口的對象,其中run函數做處理工作;

b)?Handler里面的mCallback指向的一個實現了Callback接口的對象,由其handleMessage進行處理;

c)?處理消息Handler對象對應的類繼承并實現了其中handleMessage函數,通過這個實現的handleMessage函數處理消息。

?由此可見,我們實現的handleMessage方法是優先級最低的!

?③ Handler處理完該Message (update UI) 后,Looper則設置該Message為NULL,以便回收!

?在網上有很多文章講述主線程和其他子線程如何交互,傳送信息,最終誰來執行處理信息之類的,個人理解是最簡單的方法——判斷Handler對象里面的Looper對象是屬于哪條線程的,則由該線程來執行!

①當Handler對象的構造函數的參數為空,則為當前所在線程的Looper;

②Looper.getMainLooper()得到的是主線程的Looper對象,Looper.myLooper()得到的是當前線程的Looper對象。

來講講一下handler機制

一個允許你發送和處理Message和Runable對象,每個線程都有自己的Looper,每個Looper中封裝著MessageQueue。Looper負責不斷的從自己的消息隊列里取出隊頭的任務或消息執行。每個handler也和線程關聯,Handler負責把Message和Runable

對象傳遞給MessageQueue(用到post,sendMessage等方法),而且在這些對象離開MessageQueue時,Handler負責執行他們(用到handleMessage方法)。

其中Message類就是定義了一個信息,這個信息中包含一個描述符和任意的數據對象,這個信息被用來傳遞給Handler.Message對象

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,983評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,772評論 3 422
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,947評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,201評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,960評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,350評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,406評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,549評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,104評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,914評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,089評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,647評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,340評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,753評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,007評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,834評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,106評論 2 375

推薦閱讀更多精彩內容

  • 旅行時,常有人在去景點的路上,邊步行邊問還有幾分鐘到。其實不過兩三公里的路,比平時鍛煉走一萬步所需的公里數還短。但...
    黃慢糊閱讀 267評論 2 1
  • 如果我是一個巨人,我知道 我的每一步都是生命在生長 在夕陽下我更應該斟酌 腳下的大地是否是我的故鄉 這一把雙手揉皺...
    唐啵兒閱讀 157評論 2 2
  • 文 | 江水 看著小家伙兒在身前身后的活蹦亂跳,不由得想起以前的一個驚險事件,現在回想還會倒吸一口涼氣。 那是幾年...
    梨醒醒閱讀 327評論 0 0
  • 曲終人散 旁邊躺著的艾尼亞聽到二人的對話摸不著頭緒,嘗試著坐起來,但身上的劇痛讓他用不上力氣“腹部被擊穿了,根本用...
    正反有李油閱讀 254評論 0 0
  • 工商管理學院16級新生中秋慰問座談會順利召開 (冰花通訊社記者李心怡)9月13日14:40,工商管理學院16級新生...
    東北大學2018閱讀 285評論 0 0