Handler原理(純理論存在)

Handler原理分析:


概念:

handler是Android提供給我們用來更新UI的機(jī)制,同時(shí)也是一套消息處理機(jī)制。我們可以用它發(fā)送消息也可以用它處理消息,并且通過她我們可以實(shí)現(xiàn)任意兩個(gè)線程之間的通信和數(shù)據(jù)交互。

使用場(chǎng)景:

可以解決多線程并發(fā)的問題? 假如有多個(gè)沒有枷鎖機(jī)制的線程要更新UI那么就會(huì)造成界面混亂,但是要是加鎖就會(huì)降低性能。所以Android給我們提供了handler用來更新ui。我們只需要遵守 不需要再考慮線程的問題了。

Handler的核心類:

handler 消息的操作類,用來接受發(fā)送處理消息的,內(nèi)部關(guān)聯(lián)Looper

looper 消息封裝的載體 內(nèi)部包含了一個(gè)MessageQueue,通過loop方法負(fù)責(zé)從MessageQueue讀取消息,如果有就交給Handler處理,沒有消息就阻塞。

MessageQueue 就是一個(gè)消息鏈表,負(fù)責(zé)存儲(chǔ)消息,具有先進(jìn)先出特點(diǎn),有消息過來就存起來,Looper會(huì)循環(huán)的從MessageQueue讀取消息Message 消息體,封裝了Handler發(fā)送和接收的數(shù)據(jù)。被存放在Looper的MessageQueue中。

核心類的關(guān)聯(lián):

在一個(gè)Activity中,系統(tǒng)會(huì)自動(dòng)幫用戶啟動(dòng)一個(gè)Looper對(duì)象。為了確保Looper的唯一性,通過ThreadLocal類來存儲(chǔ)Looper對(duì)象,每次在調(diào)用prepare方法創(chuàng)建Looper的時(shí)候,會(huì)先調(diào)用threadLocal類的get方法判斷是否已經(jīng)創(chuàng)建了Looper對(duì)象,如果已經(jīng)創(chuàng)建就拋出RuntimeException異常,否則就創(chuàng)建Looper對(duì)象并放入threadLocal類中,threadLocal通過靜態(tài)的內(nèi)部類ThreadLocalMap來實(shí)現(xiàn)存儲(chǔ)。

在looper的構(gòu)造函數(shù)中創(chuàng)建了對(duì)應(yīng)的MessageQueue來存儲(chǔ)Message。再調(diào)用looper方法開啟循環(huán)獲取MessageQueue中的消息。

我們使用handler來處理和發(fā)布消息,一般都是通過new一個(gè)Handler對(duì)象,并且重寫它的handleMessage方法。然后通過調(diào)用handler的sendMessage方法,傳入需要發(fā)送的消息體

Message,Message將被存入MessageQueue中。

loop通過死循環(huán)讀取MessageQueue中是否有消息,如果沒有消息進(jìn)入阻塞,否則判斷消息對(duì)象的target,也就是消息的處理者是否為空,通過msg.target找到消息的處理者,調(diào)用它的dispatchMessage方法將msg傳遞給消息的處理者。最后傳入處理消息handler的handleMessage方法,在此方法中對(duì)消息進(jìn)行相應(yīng)的消息處理。

特點(diǎn):

一個(gè)線程只有一個(gè)Looper和MessageQueue,但是可以有多個(gè)Handler。

HandlerThread 谷歌官方封裝的,用于線程間通信,比如常見的在Activity中跟新UI,涉及到子線程和主線程之間的通信。類似于AsyncTask。

HandlerThread handlerThread = new HandlerThread("handlerThread");

????????????????????????????????????handlerThread.start();

Handler handler = new Handler(handlerThread.getLooper()){

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

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

????????????????????????????super.handleMessage(msg);

? ? ? ? ? ? ? ? ? ? }

????}

為什么主線程不會(huì)因?yàn)镠andler的死循環(huán)不會(huì)被卡死

真正會(huì)卡死主線程的操作是在回調(diào)方法onCreate/onStart/onResume等操作時(shí)間過長(zhǎng),會(huì)導(dǎo)致掉幀,甚至發(fā)生ANR,looper.loop本身不會(huì)導(dǎo)致應(yīng)用卡死。

Handler常規(guī)的使用方式

private Handler mHandler = new Handler(){

? ? ? ? @Override

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

? ? ? ? ? ? super.handleMessage(msg);

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

? ? ? ? ? ? ? ? case MESSAGE_WHAT:

? ? ? ? ? ? ? ? ? ? Log.d(TAG, "main thread receiver message: " + ((String) msg.obj));

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

? ? ? ? ? ? }

? ? ? ? }

? ? };

? private void sendMessageToMainThreadByWorkThread() {

? ? ? ? new Thread(){

? ? ? ? ? ? @Override

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

? ? ? ? ? ? ? ? Message message = mHandler.obtainMessage(MESSAGE_WHAT);

? ? ? ? ? ? ? ? message.obj = "I am message from work thread";

? ? ? ? ? ? ? ? mHandler.sendMessage(message);

? ? ? ? ? ? }

? ? ? ? }.start();

? ? }

? ? /*

? ? * 通常我們?cè)谥骶€程中創(chuàng)建一個(gè)Handler,

? ? * 然后重寫該Handler的handlerMessage方法,可以看到該方法傳入了一個(gè)參數(shù)Message,

? ? * 該參數(shù)就是我們從其他線程傳遞過來的信息。

? ? * 我們?cè)趤砜聪伦泳€程中如何傳遞的信息,子線程通過Handler的obtainMessage()方法獲取到一個(gè)Message實(shí)例,

? ? * 我們來看看Message的幾個(gè)屬性:

? ? * Message.what------------------>用來標(biāo)識(shí)信息的int值,通過該值主線程能判斷出來自不同地方的信息來源

? ? * Message.arg1/Message.arg2----->Message初始定義的用來傳遞int類型值的兩個(gè)變量

? ? * Message.obj------------------->用來傳遞任何實(shí)例化對(duì)象

? ? * 最后通過sendMessage將Message發(fā)送出去。

? ? * Handler所在的線程通過handlerMessage方法就能收到具體的信息了,如何判斷信息的來源呢?當(dāng)然是通過what值啦。

? ? * 怎么樣很簡(jiǎn)單吧

? ? */

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容