在開始實(shí)現(xiàn)之前我們需要一個(gè)Handler模型進(jìn)行推導(dǎo)
ThreadLocal:
呵呵呵,沒有我你們能干啥?
synchronized:笑而不語
Lock:樓上sb?還沒被開除?
Condition:2樓sb
Handler:氣氛Hi起來!動(dòng)次打次!
Message:朋友圈幫我集個(gè)贊!
Looper:.......
MessageQueue:退群了
旁白:我們通過上圖的模型可以推導(dǎo)出,要想實(shí)現(xiàn)Handler機(jī)制少不了以下的一些隊(duì)友的配合
1.Message
TA就是一個(gè)對(duì)象,封裝了一些信息,使用者可以將自己想要的信息傳到里面去!里面只有幾個(gè)成員變量,沒別的!
private int what;//用過Handler的肯定經(jīng)常用吧
private Object;//跟上面的成員變量一個(gè)意思
private Hander target;//這是個(gè)重點(diǎn),為什么要封裝一個(gè)Handler對(duì)象呢?因?yàn)樽罱K處理消息的是Handler啊.如果沒有這個(gè)對(duì)象,我們?nèi)绾?調(diào)用)把消息傳遞給Handler的handleMessage方法呢?
2.MessageQueue
a.MessageQueue 是一個(gè)鏈表結(jié)構(gòu)的消息隊(duì)列(數(shù)組實(shí)現(xiàn))
b.主要提供存,取,對(duì)存取的線程進(jìn)行鎖控制,避免多線程并發(fā)訪問的問題.
c.MessageQueue可提供的功能列表:
void enqueueMessage(Message message);//將消息對(duì)象添加到鏈表中
Message next();//從鏈表中取出消息對(duì)象
boolean hasNext();//消息隊(duì)列中的數(shù)據(jù)是否為空
3.Looper
死循環(huán)!死循環(huán)!死循環(huán)!死循環(huán)!死循環(huán)!死循環(huán)!死循環(huán)!死循環(huán)!
Looper中可提空的功能列表:
void prepare();//初始化Looper,將Looper綁定到ThreadLocal
void loop();//開始死循環(huán)的從MessageQueue中取出消息對(duì)象.
Looper myLooper();//獲取ThreadLocal中存儲(chǔ)的Looper對(duì)象
4.Handler
負(fù)責(zé)發(fā)送消息,處理消息
可提供的功能列表:
void handleMessage(Message message);
void sendMessage(Message message);//發(fā)送消息就是將你的Message對(duì)象放到MessageQueue中去
void dispatchMessage(Message message);//沒別的,就是調(diào)用了一下handleMessage,之所以會(huì)有這個(gè)方法是因?yàn)槲覀兏侠淼倪M(jìn)行封裝.當(dāng)Looper.loop方法循環(huán)取消息時(shí)會(huì)調(diào)用這個(gè)方法.
5.ThreadLocal
在線程中扮演了很重要的角色
引:ThreadLocal是解決線程安全問題一個(gè)很好的思路急侥,它通過為每個(gè)線程提供一個(gè)獨(dú)立的變量副本解決了變量并發(fā)訪問的沖突問題。在很多情況下坏怪,ThreadLocal比直接使用synchronized同步機(jī)制解決線程安全問題更簡單绊茧,更方便,且結(jié)果程序擁有更高的并發(fā)性.
在Handler中使用ThreadLocal來進(jìn)行數(shù)據(jù)隔離,目的就是更好的隔離Looper對(duì)象,畢竟我們的Looper是存儲(chǔ)在了ThreadLocal 的map中.
6.Lock,Condition
為了解決線程鎖,隊(duì)列為空,或者滿員的問題,當(dāng)隊(duì)列為空或者隊(duì)列滿員的情況我們要通過Lock去阻塞(消息不能被添加到隊(duì)列中,取出消息的時(shí)候也同理),直到隊(duì)列中有消息被消費(fèi)了(處理了).畢竟我們得隊(duì)列長度是有限的嘛,要不然就內(nèi)存溢出了嘛,老天爺會(huì)懲罰你的嘛.
Condition:與Lock配對(duì)使用,我們這里之所以用Condition而不用synchronized的原因就是Condition 與Lock配合,可以指定"誰"來解鎖.顯而易見的用synchronized來實(shí)現(xiàn)是非常麻煩的,Lock和Condition 更適合復(fù)雜的并發(fā)場(chǎng)景.
OK!我們經(jīng)過了上面的小圖片的推導(dǎo),大體的結(jié)構(gòu)就已經(jīng)出來了
首先Handler中的代碼:
public class Handler {
private MessageQueue mMessageQueue;
private Looper myLooper;
public void handleMessage(Message message){
}
//handler 在主線程中初始化
public Handler(){
//拿到Looper
myLooper = Looper.myLooper();
//拿到Looper中的消息隊(duì)列
mMessageQueue = myLooper.messageQueue;
}
public void dispathMessage(Message message){
handleMessage(message);
}
public void sendMessage(Message message){
//發(fā)送消息就是將消息實(shí)體入隊(duì)到消息隊(duì)列中
message.target = this;
mMessageQueue.enqueueMessage(message);
}
}
Looper中的代碼:
public class Looper {
MessageQueue messageQueue;
public static void prepare(){
if (mThreadLocal.get() != null){
throw new RuntimeException("Only on Looper may be created per thread");
}
mThreadLocal.set(new Looper());
}
public Looper(){
messageQueue = new MessageQueue();
}
private static final ThreadLocal<Looper> mThreadLocal = new ThreadLocal<>();
public static void loop(){
Looper me = myLooper();
if (me ==null){
throw new RuntimeException("thread looper is null.call Looper.prepare()");
}
//獲取到loop中的消息隊(duì)列
MessageQueue messageQ = me.messageQueue;
for (;;){
if (!messageQ.hasNext()){
continue;
}else {
Message message = messageQ.next();
//如果消息為null,繼續(xù)處理下一個(gè)
if (message ==null){
continue;
}
//拿到消息,將消息發(fā)送給Handler
message.target.dispathMessage(message);
}
}
}
public static Looper myLooper(){
if (mThreadLocal.get() ==null){
throw new RuntimeException("not call Looper.prepare()");
}
return mThreadLocal.get();
}
}
Message中的代碼:
public class Message {
Handler target;//消息的處理對(duì)象
public int what;
public Object object;
@Override
public String toString() {
return object.toString()+":what:"+what;
}
}
MessageQueue中的代碼
public class MessageQueue {
/**
* 到底能不能再子線程中更新UI?
* Android 通過判斷當(dāng)前線程是否是ViewRootImpl的創(chuàng)建線程來檢查是否可以更新UI
* 調(diào)用View.addView的時(shí)候會(huì)調(diào)用初始化ViewRootImpl,也就是說如果我在子線程中addView,
* 那么我就可以在子線程中更新View.
*/
private int MAX_QUEUE = 50;
/**
* 消息隊(duì)列應(yīng)該有上限,否則會(huì)造成內(nèi)存溢出
當(dāng)隊(duì)列沒有消息的時(shí)候需要阻塞,直到有消息進(jìn)來
當(dāng)隊(duì)列消息滿的時(shí)候需要阻塞,直到有消息被處理
*/
Message[] messageQueue;
private Lock mLock;//鎖對(duì)象,為了可以控制消息隊(duì)列什么時(shí)候可以繼續(xù)出隊(duì)或者入隊(duì)
private Condition popCondition;//可以選擇性的解鎖
private Condition pushCondition;
private int messageQueueCout;//隊(duì)列中的消息的當(dāng)前是數(shù)量
private int pushIndex;//入隊(duì)時(shí)的索引
private int popIndex;//出隊(duì)時(shí)的索引
//出隊(duì)消息:運(yùn)行在子線程中
public void enqueueMessage(Message message){
try {
//加鎖類似于synchronized (),因?yàn)镃ondition可以選擇性解鎖
mLock.lock();
//當(dāng)消息隊(duì)列滿了,子線程停止發(fā)送消息,阻塞
//為了避免多個(gè)子線程同級(jí)喚醒,導(dǎo)致的單次判斷問題.使用while 不斷進(jìn)行檢查.
while (messageQueueCout == MAX_QUEUE){
pushCondition.await();
}
//將消息推進(jìn)數(shù)組中
messageQueue[pushIndex] = message;
pushIndex++;
if (pushIndex == MAX_QUEUE){
pushIndex = 0;
}
messageQueueCout++;
//如果有產(chǎn)品被生產(chǎn),通知消費(fèi)者可以繼續(xù)消費(fèi)Message
popCondition.signalAll();//??
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
mLock.unlock();
}
}
//出隊(duì)消息:運(yùn)行在主線程中(消費(fèi)隊(duì)列中的消息)
public Message next(){
Message message = null;
try {
//當(dāng)消息隊(duì)列為空的時(shí)候阻塞消費(fèi)者,讓消費(fèi)者不能繼續(xù)消費(fèi)消息
mLock.lock();
while (messageQueueCout ==0){
popCondition.await();
}
message = messageQueue[popIndex];
messageQueue[popIndex] = null;//當(dāng)一個(gè)數(shù)據(jù)被出隊(duì)時(shí),釋放內(nèi)存
popIndex++;
if (popIndex == MAX_QUEUE){
popIndex=0;
}
//當(dāng)隊(duì)列數(shù)量不滿時(shí)通知子線程可以繼續(xù)入隊(duì)消息
messageQueueCout--;
//通知生產(chǎn)者可以繼續(xù)生產(chǎn)Message
pushCondition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
mLock.unlock();
}
return message;
}
public boolean hasNext(){
return messageQueue.length!=0;
}
public MessageQueue(){
//初始化消息隊(duì)列
messageQueue = new Message[MAX_QUEUE];
mLock = new ReentrantLock();//初始化鎖對(duì)象
this.pushCondition = mLock.newCondition();
this.popCondition = mLock.newCondition();
}
}
好的!我們來寫個(gè)Main方法調(diào)用一下!
public class Main {
public static void main(String[] args) {
Looper.prepare();
Handler mHandler = new Handler(){
@Override
public void handleMessage(Message message) {
System.out.println(message);
}
};
new Thread(new Runnable() {
@Override
public void run() {
Message m = new Message();
m.object="hello";
mHandler.sendMessage(m);
}
}).start();
Looper.loop();
}
}
這就是為什么在Activity main方法中會(huì)調(diào)用 Looper.prepare()...Looper.loop();
因?yàn)槟阋獙⒆约撼志没絻?nèi)存中去嘛!要不然就死掉了嘛!
通過一個(gè)死循環(huán)+Handler
當(dāng)我們?cè)谧泳€程中創(chuàng)建Handler的時(shí)候,也要模仿Activity的Handler創(chuàng)建方式才對(duì)嘛!
在哪個(gè)線程中創(chuàng)建了Handler 對(duì)于Handler本身來說誰就是主線程.因?yàn)閷?duì)于Handler來說線程是相對(duì)關(guān)系的!
public class Activity{
public static main(String[] args){
......
Looper.prepareMainLoop();
............
Looper.loop();
}
}