簡潔移動的Java程式碼模擬Android Handler機制,值得一看!!
Handler機制簡介
Handler是android中最重要組成部分之一,Handler機制可以看做是一個訊息阻塞佇列,APP啟動後很快就進入死迴圈(while迴圈),不斷的讀取訊息佇列中的訊息,每個執行緒最多隻有一個訊息佇列,沒有訊息時就阻塞,有就立馬執行。所有訊息排隊執行,因為是一個執行緒,所以同時只能執行一個訊息。android的view繪製,事件響應(點選,觸控式螢幕幕等)都是把訊息傳送到了主執行緒的訊息佇列,等待android APP的執行(這點可以通過手動丟擲異常檢視錯誤堆疊來驗證)。包括自己在主執行緒new 的handler最終也是把訊息插入到了主執行緒訊息佇列中。從以上來看android主執行緒大部分時間是空閒的。當點選屏幕後手機能立馬響應也可以看出android主執行緒大部分時間是空閒的。雖然主執行緒要處理的事情狠多,很雜,很瑣碎(view佈局、繪製,事件分發等等),但處理時間都很短暫,可以保證很快處理完畢,然後等待下一個訊息的到來。android handler機制簡可以實現所有view相關的操作都在主執行緒進行,從而避免了使用 鎖 。具體實現程式碼 如下。
java工程實現Handler機制程式碼
下面的程式碼跟android的handler機制主要原理完全一致,但不依賴android系統。
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
import com.handler.Handler;import com.handler.Looper;import com.handler.Message;public class Main { public static void main(String[] args) { new Main().start(); } private void start(){ //建立該執行緒唯一的訊息佇列,執行緒安全的阻塞佇列 Looper.prepare(); onCreate(); //死迴圈,阻塞式,執行下面程式碼後主執行緒就會去獲取訊息佇列裡的訊息,沒有訊息時就阻塞,有就執行。執行Looper.loop前即使訊息佇列裡有訊息,訊息也不會執行,因為主執行緒還沒有去檢查訊息佇列。 |
執行結果
1234567891011121314151617 | main thread=Thread[main,5,main] current thread is main thread? true what=18175614 obj=new ThreadThread[Thread-0,5,main] Exception in thread "Thread-1" java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() at com.handler.Handler.<init>(Handler.java:14) at Main$3$1.<init>(Main.java:103) at Main$3.run(Main.java:103) current thread is main thread? true what=1 obj=hanler...waht==1 current thread is main thread? true what=2 obj=hanler...waht==2 current thread is main thread? true what=3 obj=hanler...waht==3 |
Handler程式碼
1234567891011121314151617181920212223242526272829303132333435 | package com.handler; public class Handler { private MessageQueue messageQueue; public Handler() { Looper looper=Looper.myLooper(); if (looper==null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } this.messageQueue=looper.messageQueue; } public void sendMessage(Message msg) { //Looper迴圈中發現message後,呼叫message.targer就得到了當前handler,使用taget.handleMessage //就把訊息轉發給了傳送message時的handler的handleMessage函式 msg.target=this; messageQueue.enqueueMessage(msg); } public void handleMessage(Message msg) { } } |
Looper程式碼
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748 | package com.handler;public class Looper { private static final ThreadLocal<Looper> threadLocal=new ThreadLocal<>(); /** * 儲存Message的佇列,阻塞式,沒有訊息則一直等待 */ final MessageQueue messageQueue; private Looper() { messageQueue=new MessageQueue(); } /**為該執行緒建立Looper, * 若該執行緒已經有Looper了則不需要再次呼叫prepare */ public static void prepare() { if (threadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } threadLocal.set(new Looper() ); } public static void loop() { Looper looper=myLooper(); if (looper == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } MessageQueue messageQueue=looper.messageQueue; for(;;){ Message message=messageQueue.next(); message.target.handleMessage(message); } } /** * 獲取當先執行緒的Looper * @return */ public static Looper myLooper() { return threadLocal.get(); }} |
MessageQueued程式碼
123456789101112131415161718192021222324252627282930313233343536 | package com.handler; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class MessageQueue { private BlockingQueue<Message>blockingQueue=new LinkedBlockingQueue<>(); /** * 阻塞式,沒有訊息則一直等待 * @return */ public Message next() { try { return blockingQueue.take(); } catch (InterruptedException e) { throw new RuntimeException(); } } /** * 插入到訊息佇列尾部 * @param message */ void enqueueMessage(Message message) { try { blockingQueue.put(message); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } |
ThreadLocal簡單實現
ThreadLocal內部原理和下面實現方式不同,但達到的效果是相同的,本篇主要介紹Handler機制,簡化了ThreadLocal
1234567891011121314151617181920212223242526272829 | package com.handler; import java.util.HashMap; import java.util.Map; /** * ThreadLocal簡單實現 * @author Young * * @param <T> */ public class ThreadLocal<T> { private Map<Thread,T>map; public ThreadLocal() { map=new HashMap<>(); } public void set(T obj) { map.put(Thread.currentThread(),obj); } public T get() { return map.get(Thread.currentThread()); } } |
Message程式碼
123456789101112131415 | package com.handler; public class Message { Handler target; public Object obj; public int what; public String toString() { return "what="+what+" obj="+obj.toString(); } } |
以上就是android Handler機制原理程式碼了。
android還提供了HandlerThread,其實是對Handler和Thread的封裝。
先看一下HandlerThread使用方式
123456789101112131415161718 | Handler myHandler; |