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)單吧
? ? */