Handler機制簡介
Handler是android中最重要組成部分之一鞭铆,Handler機制可以看做是一個消息阻塞隊列撵溃,APP啟動后很快就進入死循環(huán)(while循環(huán)),不斷的讀取消息隊列中的消息,每個線程最多只有一個消息隊列,沒有消息時就阻塞了牛,有就立馬執(zhí)行。所有消息排隊執(zhí)行辰妙,因為是一個線程,所以同時只能執(zhí)行一個消息甫窟。android的view繪制密浑,事件響應(點擊,觸摸屏幕等)都是把消息發(fā)送到了主線程的消息隊列粗井,等待android APP的執(zhí)行(這點可以通過手動拋出異常查看錯誤堆棧來驗證)尔破。包括自己在主線程new 的handler最終也是把消息插入到了主線程消息隊列中。從以上來看android主線程大部分時間是空閑的浇衬。當點擊屏幕后手機能立馬響應也可以看出android主線程大部分時間是空閑的懒构。雖然主線程要處理的事情狠多,很雜耘擂,很瑣碎(view布局胆剧、繪制,事件分發(fā)等等),但處理時間都很短暫秩霍,可以保證很快處理完畢篙悯,然后等待下一個消息的到來。android handler機制簡可以實現(xiàn)所有view相關的操作都在主線程進行铃绒,從而避免了使用 鎖 鸽照。具體實現(xiàn)代碼 如下。
java工程實現(xiàn)Handler機制代碼
下面的代碼跟android的handler機制主要原理完全一致颠悬,但不依賴android系統(tǒng)矮燎。
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(){
//創(chuàng)建該線程唯一的消息隊列,線程安全的阻塞隊列
Looper.prepare();
onCreate();
//死循環(huán)赔癌,阻塞式诞外,執(zhí)行下面代碼后主線程就會去獲取消息隊列里的消息,沒有消息時就阻塞届榄,有就執(zhí)行浅乔。執(zhí)行Looper.loop前即使消息隊列里有消息,消息也不會執(zhí)行铝条,因為主線程還沒有去檢查消息隊列靖苇。
Looper.loop();
//下面 的代碼通常不會執(zhí)行,除非手動讓主線程消息隊列退出班缰。退出主線程消息隊列后android的view布局贤壁、繪制,事件分發(fā)就不執(zhí)行了埠忘,所以android APP也沒必要繼續(xù)執(zhí)行了脾拆,所以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()莹妒,則證明已經(jīng)運行在主線程中了
System.out.println("current thread is main thread? " + (thread == Thread.currentThread()));
System.out.println(msg);
System.out.println();
}
};
// 測試1 主線程創(chuàng)建handler名船,子線程使用該handler發(fā)送消息
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();
//在子線程中發(fā)送消息
handler.sendMessage(message);
try {
Thread.sleep(1000 * 2);
} catch (InterruptedException e) {
}
message = new Message();
message.obj = "hanler...waht==1" ;
message.what = 1;
//在子線程中發(fā)送消息
handler.sendMessage(message);
message = new Message();
message.obj = "hanler...waht==2" ;
message.what = 2;
//在子線程中發(fā)送消息
handler.sendMessage(message);
message = new Message();
message.obj = "hanler...waht==3" ;
message.what = 3;
//在子線程中發(fā)送消息
handler.sendMessage(message);
};
}.start();
// 測試2 在thread內部創(chuàng)建handler,結果會拋出異常
new Thread() {
public void run() {
try {
sleep(1000 * 3);
} catch (InterruptedException e) {
}
/*
* 在線程內部使用默認構造函數(shù)創(chuàng)建handler會拋出異常旨怠。
* android中也可以在子線程中創(chuàng)建Handler渠驼,但要在初始化時傳入Looper,
* Looper.getMainLooper()獲取到的就是主線程的Looper鉴腻,所以可以這樣創(chuàng)建
*
* 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();
//在子線程中發(fā)送消息
h.sendMessage(message);
};
}.start();
//////////////////////////////////////////////////////////
////// 上面的操作相當于運行在android的UI線程中 ////////////
//////////////////////////////////////////////////////////
}
}
運行結果
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代碼
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循環(huán)中發(fā)現(xiàn)message后迷扇,調用message.targer就得到了當前handler,使用taget.handleMessage
//就把消息轉發(fā)給了發(fā)送message時的handler的handleMessage函數(shù)
msg.target=this;
messageQueue.enqueueMessage(msg);
}
public void handleMessage(Message msg) {
}
}
Looper代碼
package com.handler;
public class Looper {
private static final ThreadLocal<Looper> threadLocal=new ThreadLocal<>();
/**
* 存儲Message的隊列爽哎,阻塞式蜓席,沒有消息則一直等待
*/
final MessageQueue messageQueue;
private Looper() {
messageQueue=new MessageQueue();
}
/**為該線程創(chuàng)建Looper,
* 若該線程已經(jīng)有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代碼
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簡單實現(xiàn)
ThreadLocal內部原理和下面實現(xiàn)方式不同厨内,但達到的效果是相同的,本篇主要介紹Handler機制,簡化了ThreadLocal
package com.handler;
import java.util.HashMap;
import java.util.Map;
/**
* ThreadLocal簡單實現(xiàn)
* @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代碼
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使用方式
Handler myHandler;
new HandlerThread("Compress-Thread") {
@Override
protected void onLooperPrepared() {
super.onLooperPrepared();
myHandler = new Handler();
myHandler.post(new Runnable(){
@Override
public void run() {
//在HandlerThread線程執(zhí)行
}
});
}
}.start();
//不要在這使用myHandler發(fā)送消息丑掺,因為myHandler是在onLooperPrepared中創(chuàng)建的获印,onLooperPrepared又是運行在HandlerThread線程的,所以剛執(zhí)行到這時HandlerThread線程可能還沒有創(chuàng)建完街州,onLooperPrepared也就不會執(zhí)行兼丰,myHandler自然是null
每次new HandlerThread都會創(chuàng)建一個新線程,當我們使用myHandler發(fā)送消息時消息就會在HandlerThread線程執(zhí)行唆缴。HandlerThread線程內部也是一個死循環(huán)鳍征,通常不會退出,當通過myHandler為其發(fā)送消息時就會從阻塞中醒來執(zhí)行消息面徽,執(zhí)行完消息隊列里的消息后就又阻塞艳丛。HandlerThread可以排隊執(zhí)行消息,保證能按加入消息的先后順序執(zhí)行趟紊。比如我們需要壓縮很多圖片時氮双,就可以使用HandlerThread,主線程直接把圖片通過myHandler發(fā)送到HandlerThread霎匈,HandlerThread就可以執(zhí)行圖片壓縮戴差,所有壓縮任務都按添加順序依次執(zhí)行。
來自我的博客
http://blog.csdn.net/qingchunweiliang/article/details/50448365