從原始碼的角度理解Android訊息處理機制

2021-07-10 09:00:46 字數 4171 閱讀 5360

與handler共同作用的有looper,messagequeue,message。我麼接下來從原始碼的角度看看整個過程的大概實現。首先說一下每個物件的作用:

looper:訊息輪詢循器,不斷的從訊息佇列中取出訊息交給handler處理

messagequeue:訊息佇列,用於儲存從handler傳送過來的訊息

message:訊息物件,可以攜帶資料

handler:用於傳送和處理訊息

在android中,主線程預設已經建立了looper和messagequeue物件,我們去分析一下。

activitythread代表了主線程物件,它的main方法是應用程式的入口,在main方法中建立了looper。

looper.preparemainlooper();

activitythread thread

=new activitythread();

looper.

loop();

我們看看preparemainlooper的實現

public

static

void

preparemainlooper()

smainlooper = mylooper();

}}

呼叫了帶引數的prepare方法

private

static

void

prepare(boolean quitallowed)

//將looper儲存在threadlocal中

sthreadlocal.set(new looper(quitallowed));

}

我們看看looper的構造方法

private

looper(boolean quitallowed)

最後是mylooper()方法

public

static @nullable looper mylooper()

threadlocal有什麼作用呢?下面大概介紹一下

threadlocal是乙個執行緒內部的資料儲存類,通過它可以在指定的執行緒中儲存資料,資料儲存以後,只有在指定執行緒中可以獲取到儲存的資料,對於其它執行緒來說無法獲取到資料,threadlocal可以在不同的執行緒之中互不干擾地儲存並提供資料,通過threadlocal可以輕鬆獲取每個執行緒的looper。

總結:looper.preparemainlooper()方法做了三件事

public static void

loop()

//取出looper對應的訊息佇列,訊息佇列是在looper的建構函式中建立的

final messagequeue queue

= me.mqueue;

......//死迴圈,可能阻塞,作用是不斷從訊息佇列取訊息

for (;;)

......//呼叫訊息物件的target的dispatchmessage方法分發訊息

//其實這個target是handler物件,後面我們會看到

msg.target.dispatchmessage(msg);

...... }

}

接下來我們看看這個msg.target是如何被賦值的,這就要從傳送訊息的過程開始分析。首先需要建立handler物件

public

handler()

public

handler(callback callback, boolean async)

}mlooper = looper.mylooper();

if (mlooper == null)

//將looper中的訊息佇列與當前handler關聯

mqueue = mlooper.mqueue;

mcallback = callback;

masynchronous = async;

}

有了handler物件,我們開始傳送訊息,我們一般採用下面的方式傳送訊息

public

final

boolean

sendemptymessage(int what)

我們繼續跟進原始碼

public

final

boolean

sendemptymessagedelayed(int what, long delaymillis)

public

final

boolean

sendmessagedelayed(message msg, long delaymillis)

return sendmessageattime(msg, systemclock.uptimemillis() + delaymillis);

}

繼續往下看

public

boolean

sendmessageattime(message msg, long uptimemillis)

return enqueuemessage(queue, msg, uptimemillis);

}

接下類看看enqueuemessage方法

private

boolean

enqueuemessage(messagequeue queue, message msg, long uptimemillis)

return queue.enqueuemessage(msg, uptimemillis);

}

在enqueuemessage方法中,我們終於證實了msg.target是乙個handler物件,接下來呼叫了訊息佇列的enqueuemessage方法

//此方法的作用是將訊息插入到訊息佇列中,訊息佇列是線性鍊錶結構

boolean enqueuemessage(message msg, long when)

if (msg.isinuse())

synchronized (this)

msg.markinuse();

msg.when = when;

message p = mmessages;

boolean needwake;

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

if (needwake && p.isasynchronous())

}msg.next = p; // invariant: p == prev.next

prev.next = msg;

}// we can assume mptr != 0 because mquitting is false.

if (needwake)

}return

true;

}

最後我們就要知道訊息是在何時被處理的,也就是說handlemessage方法在何處被呼叫的,我們知道,在looper的loop()方法中呼叫了下面的**

msg.target

.dispatchmessage(msg);

也就是looper所關聯的handler物件的dispatchmessage方法

public

void

dispatchmessage(message msg) else

}handlemessage(msg);

}}

看到了吧,終於發現了handlemessage方法的呼叫。

用到handler,需要對比一下近似方法:

a.activity,runonuithread(runnnable)

view.post

view.postdelayed

b.handler類

c.asynctask

這三種方法實際上都是基於handler類演變而來,只是表現形式不一樣,比如asynctask是對handler和thread的乙個封裝。三種方式區別

從原始碼的角度理解Volley

今天從原始碼的角度來理解一下volley中部分功能的實現。新增請求到請求佇列 將請求新增到請求佇列中 public requestadd requestrequest 為請求設定順序編號.request.setsequence getsequencenumber 新增標記 request.addma...

從原始碼角度來看UVM phase

說到uvm phase我們就知道是uvm乙個很重要的特性,從使用者角度來講,其實就是一些很簡單的應用規則,能夠極大地提公升編碼的效率,簡化 複雜度,提高debug的效率。至於應用可以參看zhangqiang大佬的第五章,這裡就不再贅述。本文就從原始碼的角度來看,uvm的phase是怎麼工作的?之前學...

從原始碼角度分析RACObserve的實現原理(一)

racobserve是個巨集,racobserve target,keypath 最終是執行 target rac valuesforkeypath keypath target,keypath observer self 這就牽出nsobject racpropertysubscribing ca...