二、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,訊息處理物件以及...