Handler機制 3 Message簡介

2021-10-21 11:57:21 字數 3843 閱讀 5068

二、message

概述message是負責承載訊息的類,主要是關注他的內部屬性:

// 使用者自定義,主要用於辨別message的型別

public int what;

// 用於儲存一些整型資料

public int arg1;

public int arg2;

// 可放入乙個可序列化物件

public object obj;

// bundle資料

bundle data;

// message處理的時間。相對於1970.1.1而言的時間

// 對使用者不可見

public long when;

// 處理這個message的handler

// 對使用者不可見

handler target;

// 當我們使用handler的post方法時候就是把runnable物件封裝成message

// 對使用者不可見

runnable callback;

// messagequeue是乙個鍊錶,next表示下乙個

// 對使用者不可見

message next;

迴圈利用message

當我們獲取message的時候,官方建議是通過message.obtain()方法來獲取,當使用完之後使用recycle()方法來**迴圈利用。而不是直接new乙個新的物件:

public static message obtain()

}return new message();

}message維護了乙個靜態鍊錶,煉表頭是spool,message有乙個next屬性,message本身就是鍊錶結構。spoolsync是乙個object物件,僅作為解決併發訪問安全設計。當我們呼叫obtain來獲取乙個新的message的時候,首先會檢查鍊錶中是否有空閒的message,如果沒有則新建乙個返回。

當我們使用完成之後,可以呼叫message的recycle方法進行**:

public void recycle()

return;

}recycleunchecked();

}如果這個message正在使用則會丟擲異常,否則則呼叫recycleunchecked進行**:

void recycleunchecked() }}

這個方法的邏輯也非常簡單,把message中的內容清空,然後判斷鍊錶是否達到最大值(50),然後插入鍊錶中。

message總結

message的作用就是承載訊息,他的內部有很多的屬性用於給使用者賦值。同時message本身也是乙個鍊錶結構,無論是在messagequeue還是在message內部的**機制,都是使用這個結構來形成鍊錶。同時官方建議不要直接初始化message,而是通過message.obtain()方法來獲取乙個message迴圈利用。一般來說我們不需要去呼叫recycle進行**,在looper中會自動把message進行**,後面會講到。

三、messagequeue

概述每個執行緒都有且只有乙個messagequeue,他是乙個用於承載訊息的佇列,內部使用鍊錶作為資料結構,所以待處理的訊息都會在這裡排隊。前面講到threadlocalmap是乙個「修改版的hashmap」,而messagequeue就是乙個「修改版的linkqueue」。他也有兩個關鍵的方法:入隊(enqueuemessage)和出隊(next)。這也是messagequeue的重點所在。

message還涉及到乙個關鍵概念:執行緒休眠。當messagequeue中沒有訊息或者都在等待中,則會將執行緒休眠,讓出cpu資源,提高cpu的利用效率。進入休眠後,如果需要繼續執行**則需要將執行緒喚醒。當方法暫時無法直接返回需要等待的時候,則可以將執行緒阻塞,即休眠,等待被喚醒繼續執行邏輯。這部分內容也會在後面詳細講。

關鍵方法

出隊 – next()

next方法主要是做訊息出隊工作。

message next()

...// 阻塞時間

int nextpolltimeoutmillis = 0;

for (;;)

// 阻塞對應時間 

nativepollonce(ptr, nextpolltimeoutmillis);

// 對messagequeue進行加鎖,保證執行緒安全

synchronized (this) else else

msg.next = null;

msg.markinuse();

return msg;

}} else

...}

}**很長,其中還涉及了同步屏障和idlehandler,這兩部分內容我放在後面講,這裡先講主要的出隊邏輯。**中我都加了注釋,這裡還是再講一下。next方法目的是獲取messagequeue中的乙個message,如果佇列中沒有訊息的話,就會把方法阻塞住,等待新的訊息來喚醒。主要步驟如下:

如果looper已經退出了,直接返回null

進入死迴圈,直到獲取到message或者退出

迴圈中先判斷是否需要進行阻塞,阻塞結束後,對messagequeue進行加鎖,獲取message

如果messagequeue中沒有訊息,則直接把執行緒無限阻塞等待喚醒;

如果messagequeue中有訊息,則判斷是否需要等待,否則則直接返回對應的message。

可以看到邏輯就是判斷當前時間message中是否需要等待。其中nextpolltimeoutmillis表示阻塞的時間,-1表示無限時間,只有通過喚醒才能打破阻塞。

入隊 – enqueuemessage()

messagequeue.class

boolean enqueuemessage(message msg, long when)

if (msg.isinuse())

// 對messagequeue進行加鎖

synchronized (this)

// 標記message正在被執行,以及需要被執行的時間,這裡的when是距離1970.1.1的時間

msg.markinuse();

msg.when = when;

// p是messagequeue的煉表頭

message p = mmessages;

boolean needwake;

// 判斷是否需要喚醒messagequeue

// 如果有新的隊頭,同時messagequeue處於阻塞狀態則需要喚醒佇列

if (p == null || when == 0 || when < p.when) else

...}

msg.next = p; 

prev.next = msg;

}// 如果需要則喚醒佇列

if (needwake)

}return true;

}這部分的**好像也很多,但是邏輯也是不複雜,主要就是鍊錶操作以及判斷是否需要喚醒messagequeue,**中我加了一些注釋,下面再總結一下:

首先判斷message的目標handler不能為空且不能正在使用中

對messagequeue進行加鎖

判斷目標執行緒是否已經死亡,死亡則直接返回false

初始化message的執行時間以及標記正在執行中

然後根據message的執行時間,找到在鍊錶中的插入位置進行插入

同時判斷是否需要喚醒messagequeue。有兩種情況需要喚醒:當新插入的message在煉表頭時,如果messagequeue是空的或者正在等待下個任務的延遲時間執行,這個時候就需要喚醒messagequeue。

messagequeue總結

message兩大重點:阻塞休眠和佇列操作。基本都是圍繞著兩點來展開。而原始碼中還涉及到了同步屏障以及idlehandler,這兩部分內容我分開到了最後一部分的相關問題中講。平時用的比較少,但也是比較重要的內容。

handler通訊機制

android應用開發有個預設規則,不在ui執行緒做耗時操作。耗時操作結果反饋給使用者也不能直接更新ui。耗時操作必須開子執行緒去做,實現的方式很多,handler asynctask service。每個人偏好不同,但是各有各的優點,根據不同的需求選擇適當的實現方式,是我一直追求的目標,每一種至少...

Handler機制概要

簡而言之,每個thread裡面有looper 通過prepare初始化,通過loop進入死迴圈 每個handler將自己的msg放入looper死迴圈裡面,然後looper迴圈檢測訊息再傳送回給handler。記憶體洩漏問題 這裡需要注意乙個記憶體洩漏問題,就是當activity退出的時候會出現記憶...

Handler機制整理

handler機制整理 目錄介紹 1.關於handler訊息機制圖 2.關於handler基本介紹 3.使用handler的幾種方法 4.關於handler底層原始碼解讀 1.關於handler訊息機制圖 2.關於handler機制基本解讀 message 訊息,其中包含了訊息id,訊息處理物件以及...