10.1 消息機制概述
-
基本概念
- android消息機制就是Handler運行機制脓鹃,Handler的運行需要底層的MessageQueue和Looper的支撐。
- MessageQueue內(nèi)部的數(shù)據(jù)結(jié)構(gòu)是單鏈表瑟慈,對外是以消息隊列的形成存在,提供插入和刪除Message操作屋匕。
- Looper以無限循環(huán)的方式去MessageQueue查找有沒有新的Message葛碧,如果有就處理,如果沒有就等待过吻。
-
Handler的主要作用是將一個任務(wù)切換到某個指定的線程中去執(zhí)行进泼。
- android 規(guī)定 UI只能主線程進行蔗衡。會在ViewRootImpl的checkThread中驗證Ui操作的線程。
- 為什么UI只能在主線程操作呢乳绕?因為UI組件非線程安全绞惦,多線程并發(fā)會有不可預(yù)期的問題;而如果加鎖處理洋措,會影響UI訪問效率济蝉。
Handler的創(chuàng)建會采用當前線程的Looper來構(gòu)建消息循環(huán)系統(tǒng),所以建立Handler前必須要已經(jīng)創(chuàng)建好Looper菠发。
10.2 消息機制分析
10.2.1 ThreadLocal的工作原理
- 當某些數(shù)據(jù)以線程為作用域而且不同線程具有不同的線程副本時王滤,可以考慮才有ThreadLocal.
- ThreadLocal是一個線程內(nèi)部的數(shù)據(jù)存儲類,通過它可以在指定的線程中存儲數(shù)據(jù)滓鸠;也只有在指定的線程中才可以獲取到存儲的數(shù)據(jù)雁乡,其他線程中無法獲得到數(shù)據(jù)。
- ThreadLocal原理
- set方法邏輯
- 找到Thread
- 找到Thread內(nèi)的localValues糜俗,如果為空踱稍,則初始化
- 根據(jù)reference——index,向tables[index+1]中存儲數(shù)據(jù)
我們可以看到悠抹,localValues是Thread對象的一個Values類型的屬性珠月。public void set(T value) { Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values == null) { values = initializeValues(currentThread); } values.put(this, value); } Values values(Thread current) { return current.localValues; } Values initializeValues(Thread current) { return current.localValues = new Values(); }
localValues中有一個數(shù)組 Object[] table,ThreadLocal存儲的值就存在這個table中,且table[index+1] = value(index為threadlocal.reference)- get方法邏輯
- 找到Thread
- 找到Thread內(nèi)的localValues楔敌,如果為空桥温,則初始化localValues,并返回initialValue梁丘。
- 如果localValus不為空,根據(jù)reference——index旺韭,從tables[index+1]中取出數(shù)據(jù)
public T get() { // Optimized for the fast path. Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values != null) { Object[] table = values.table; int index = hash & values.mask; if (this.reference == table[index]) { return (T) table[index + 1]; } } else { values = initializeValues(currentThread); } return (T) values.getAfterMiss(this); }
- set方法邏輯
10.2.2 消息隊列的工作原理
- MessageQueue的數(shù)據(jù)結(jié)構(gòu)主要是單鏈表氛谜,實現(xiàn)了enqueueMessage(插入)和next(讀取和刪除)動作
- 從原理上看
- enqueueMessage就是單鏈表的插入動作
- next是一個無限的循環(huán),當有消息到來区端,next方法會返回這條消息并將其從單鏈表中移除值漫;如果沒有消息到來,next方法就會一直阻塞在這里
10.2.3 Looper的工作原理
- 基本使用
new Thread("test"){
@Override
public void run() {
Looper.prepare();//創(chuàng)建looper
Handler handler = new Handler();//可以創(chuàng)建handler了
Looper.loop();//開始looper循環(huán)
}
}.start();
- 主線程的Looper開發(fā)者一般不需要去prepare织盼,已經(jīng)由ActivityThread通過prepareMainLooper()創(chuàng)建好了杨何。
- Looper提供一個getMainLooper()方法,這樣就可以在任何地方獲得主線程Looper沥邻。
- Looper有quit()和quitSafely()危虱。quitSafely需要將消息全部處理完畢后才安全退出。
- 在不需要一直輪尋的時候唐全,要適時quit Looper埃跷。
- 當Looper調(diào)用loop()方法之后蕊玷,消息循環(huán)系統(tǒng)才真正的起左右。
Looper的loop方法會調(diào)用MessageQueue的next方法來獲取新消息弥雹,而next是一個阻塞操作垃帅,當沒有消息時,next方法會一直阻塞著在那里剪勿,這也導(dǎo)致了loop方法一直阻塞在那里贸诚。如果MessageQueue的next方法返回了新消息,Looper就會處理這條消息:msg.target.dispatchMessage(msg)厕吉,其中的msg.target就是發(fā)送這條消息的Handler對象酱固。
10.2.4 Handler工作原理
- Handler就是處理消息的發(fā)送和接收之后的處理;
- Handler處理消息的過程
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);//當message是runnable的情況赴涵,也就是Handler的post方法傳遞的參數(shù)媒怯,這種情況下直接執(zhí)行runnable的run方法
} else {
if (mCallback != null) {//如果創(chuàng)建Handler的時候是給Handler設(shè)置了Callback接口的實現(xiàn),那么此時調(diào)用該實現(xiàn)的handleMessage方法
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);//如果是派生Handler的子類髓窜,就要重寫handleMessage方法扇苞,那么此時就是調(diào)用子類實現(xiàn)的handleMessage方法
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
3.Handler還有一個特殊的構(gòu)造方法,它可以通過特定的Looper來創(chuàng)建Handler寄纵。
public Handler(Looper looper){
this(looper, null, false);
}
10.3 主線程的消息循環(huán)
- Android的主線程就是ActivityThread鳖敷,主線程的入口方法就是main,其中調(diào)用了Looper.prepareMainLooper()來創(chuàng)建主線程的Looper以及MessageQueue程拭,并通過Looper.loop()方法來開啟主線程的消息循環(huán)定踱。
- 主線程內(nèi)有一個Handler,即ActivityThread.H恃鞋,它定義了一組消息類型崖媚,主要包含了四大組件的啟動和停止等過程,例如LAUNCH_ACTIVITY等恤浪。
- ActivityThread通過ApplicationThread和AMS進行進程間通信畅哑,AMS以進程間通信的方法完成ActivityThread的請求后會回調(diào)ApplicationThread中的Binder方法,然后ApplicationThread會向H發(fā)送消息水由,H收到消息后會將ApplicationThread中的邏輯切換到ActivityThread中去執(zhí)行荠呐,即切換到主線程中去執(zhí)行,這個過程就是主線程的消息循環(huán)模型砂客。