1. 程式人生 > >簡潔移動的Java程式碼模擬Android Handler機制,值得一看!!

簡潔移動的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前即使訊息佇列裡有訊息,訊息也不會執行,因為主執行緒還沒有去檢查訊息佇列。
Looper.loop(); //下面 的程式碼通常不會執行,除非手動讓主執行緒訊息佇列退出。退出主執行緒訊息佇列後android的view佈局、繪製,事件分發就不執行了,所以android APP也沒必要繼續執行了,所以android採用了丟擲異常的方式結束APP。 System.out.println("exit........"); throw new RuntimeException("Main thread loop unexpectedly exited"); } private void onCreate() { ////////////////////////////////////////////////////////// ////// 下面的操作相當於執行在android的UI執行緒中 //////////// ////////////////////////////////////////////////////////// final Thread thread = Thread.currentThread(); System.out.println("main thread=" + thread); Handler handler = new Handler() { @Override public void handleMessage(Message msg) { //若thread == Thread.currentThread(),則證明已經執行在主執行緒中了 System.out.println("current thread is main thread? " + (thread == Thread.currentThread())); System.out.println(msg); System.out.println(); } }; // 測試1 主執行緒建立handler,子執行緒使用該handler傳送訊息 new Thread() { public void run() { try {//模擬耗時操作 Thread.sleep(1000 * 2); } catch (InterruptedException e) { } Message message = new Message(); message.obj = "new Thread" + Thread.currentThread(); message.what = (int) System.currentTimeMillis(); //在子執行緒中傳送訊息 handler.sendMessage(message); try { Thread.sleep(1000 * 2); } catch (InterruptedException e) { } message = new Message(); message.obj = "hanler...waht==1" ; message.what = 1; //在子執行緒中傳送訊息 handler.sendMessage(message); message = new Message(); message.obj = "hanler...waht==2" ; message.what = 2; //在子執行緒中傳送訊息 handler.sendMessage(message); message = new Message(); message.obj = "hanler...waht==3" ; message.what = 3; //在子執行緒中傳送訊息 handler.sendMessage(message); }; }.start(); // 測試2 在thread內部建立handler,結果會丟擲異常 new Thread() { public void run() { try { sleep(1000 * 3); } catch (InterruptedException e) { } /* * 線上程內部使用預設建構函式建立handler會丟擲異常。 * android中也可以在子執行緒中建立Handler,但要在初始化時傳入Looper, * Looper.getMainLooper()獲取到的就是主執行緒的Looper,所以可以這樣建立 * * new Handler(Looper.getMainLooper()){ @Override public void handleMessage(Message msg) { //執行在主執行緒中 } }; */ Handler h = new Handler() { public void handleMessage(Message msg) { System.out.println("haneler msg...." + msg); }; }; Message message = new Message(); message.obj = "handler in new Thread"; message.what = (int) System.currentTimeMillis(); //在子執行緒中傳送訊息 h.sendMessage(message); }; }.start(); ////////////////////////////////////////////////////////// ////// 上面的操作相當於執行在android的UI執行緒中 //////////// ////////////////////////////////////////////////////////// }}

執行結果

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; @Override public String toString() { return "what="+what+" obj="+obj.toString(); } }

以上就是android Handler機制原理程式碼了。

android還提供了HandlerThread,其實是對Handler和Thread的封裝。

先看一下HandlerThread使用方式

123456789101112131415161718 Handler myHandler;