Handler是什么?
Android中的異步消息處理機(jī)制,使用者可以在不阻塞UI線程的前提下輕松的實(shí)現(xiàn)消息管理和發(fā)送。
原理:
handler機(jī)制中包含4個(gè)關(guān)鍵類(下面對(duì)源碼的解析也是從這4個(gè)類入手),Message(消息),MessageQueue(消息隊(duì)列),Looper(輪詢器),Handler(消息發(fā)送和接收并處理),簡(jiǎn)單一句話概括就是:handler負(fù)責(zé)發(fā)送message,將其加入到MessageQueue中,Looper不間斷的從MessageQueue中取出消息,并發(fā)送給對(duì)應(yīng)的handler實(shí)例去處理。
重點(diǎn):源碼解析
有些同學(xué)不知道如何去看源碼,這就很尷尬了,往往想知道系統(tǒng)里面的源碼或者牛逼的開源項(xiàng)目是如何設(shè)計(jì)的,但是就是不知道如何入手,還有些同學(xué)覺得看源碼沒用,懂得怎么用不就行了嗎,非也,懂得如何用那只是招式,可能換個(gè)地方換種形式你就不認(rèn)識(shí)了,懂源碼,那是心法,知其所以然,才能千變?nèi)f化!
首先,我們使用的時(shí)候是這樣的:
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
//消息處理
·········
}
};
Message msg = Message.obtain();
handler.sendMessage(Message msg);
定義一個(gè)handler,并重寫了他的handleMessage()方法;我們來看看它的構(gòu)造方法:
public Handler() {
this(null, false);
}
public Handler(Callback callback) {
this(callback, false);
}
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
@hide
public Handler(boolean async) {
this(null, async);
}
@hide
public Handler(Callback callback, boolean async) {
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
@hide
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
蒙蔽了,這么多!但是注意,后面三個(gè)你都是沒法使用的,因?yàn)橛蠤hide;
先看空參構(gòu)造,他直接調(diào)用了Handler(Callback callback, boolean async);看看里面做了什么:
- 獲取looper對(duì)象:Looper.myLooper(); 進(jìn)去可以看到 返回了,sThreadLocal.get();這個(gè)是什么玩意?ThreadLocal,他是一個(gè)容器,里面封裝了一個(gè)map,以當(dāng)前線程的ThreadLocal作為key,以你要存的值作為value,我們這里value就是looper對(duì)象,這個(gè)容器是專門用來保存線程所特有的變量的,起到了線程間隔離的作用,如果有人想知道,我專門開一篇博客來講。至于looper是怎么初始化的,客官莫急,下面會(huì)講。
- mQueue = mLooper.mQueue;拿到消息隊(duì)列,這是一個(gè)鏈表結(jié)構(gòu),注:一個(gè)線程對(duì)應(yīng)一個(gè)looper,一個(gè)looper同樣也只有一個(gè)queue;
- callback這個(gè)是handler里面的一個(gè)接口,在消息分發(fā)的時(shí)候會(huì)講到,默認(rèn)是null,mAsynchronous這個(gè)參數(shù)表示消息是否是異步消息,默認(rèn)是false;
接下來看Message.obtain():
public static Message obtain() {
synchronized (sPoolSync) { //同步代碼塊
if (sPool != null) {
Message m = sPool; //sPool是一個(gè)靜態(tài)的Message 引用
sPool = m.next; //next也是Message,但是他不是靜態(tài)的;
m.next = null;
m.flags = 0;
sPoolSize--;
return m;
}
}
return new Message();
}
obtain()的實(shí)現(xiàn)非常有意思,我們知道m(xù)essage其實(shí)是復(fù)用的,message中有一個(gè)方法:recycle(),大家可以去看一下,消息被處理完畢后會(huì)調(diào)用recycle()方法,將message還原,并將sPool這個(gè)賦值為this,也就是當(dāng)前自己的實(shí)例對(duì)象,如果sPool是null那么當(dāng)前沒有消息可以復(fù)用,直接new出來并返回,如果不是null,那么將當(dāng)前的sPool返回,那么這個(gè)next又是干什么的呢?代碼可見,sPool =m.next;將sPool重新賦值,這個(gè)m.next就是一條將要處理的消息,也就是說每一個(gè)msg里面都有對(duì)下一個(gè)將要處理的消息的引用,這樣,sPool被賦值了,下次再執(zhí)行obtain()的時(shí)候,sPool指向的其實(shí)是另外一個(gè)Message實(shí)例了,至于next如何賦值,稍后在MessageQueue中詳細(xì)解析。
Message拿到了,開始發(fā)消息吧,sendMessage(Message msg);
public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg, 0); //直接調(diào)用sendMessageDelayed方法
}
通過源碼,一層一層往下找,發(fā)現(xiàn):sendMessage ——> sendMessageDelayed ——>sendMessageAtTime
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
//此方法才是真正發(fā)消息
MessageQueue queue = mQueue; //先拿消息隊(duì)列
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this; //重點(diǎn):this表示的是當(dāng)前的handler實(shí)例,每個(gè)message都會(huì)記錄發(fā)送它的那個(gè)handler
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis); //這里調(diào)用了messageQueue的方法;
}
重點(diǎn):為什么msg要保存handler的引用呢?
我們都知道,handler機(jī)制消息處理,哪一個(gè)handler實(shí)例發(fā)出的消息,那么那一個(gè)handler就負(fù)責(zé)處理這個(gè)消息,這里的msg.target = this; 作用就在這,用來記住誰將msg發(fā)出來,等到處理的時(shí)候誰就來處理。
接著分析,handler最后調(diào)用了queue.enqueueMessage(msg, uptimeMillis);
我們來看看這個(gè)方法:(比較多,我精簡(jiǎn)了一下,留下重要的部分)
boolean enqueueMessage(Message msg, long when) {
msg.markInUse();
msg.when = when;
Message p = mMessages;//當(dāng)前將要被處理的msg
boolean needWake;
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p;
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
mMessages是即將要處理的message,先看第一個(gè)if最有一個(gè)條件,when<p.when,這個(gè)when是什么呢,它是一個(gè)時(shí)間毫秒值,when = 發(fā)送消息的那一刻的時(shí)間+delytime(延后的時(shí)間);表示這個(gè)msg將要在什么時(shí)刻可以被處理,when越小,越要被有先處理,所以,if判斷新來的msg是否優(yōu)先級(jí)比當(dāng)前即將要被處理的高,如果是,那么將此消息放在第一位(mMessages = msg),并且還做了另外一件事,msg.next = p; p下一個(gè)要處理的msg,else里面道理也是一樣的,for循環(huán)比較
重點(diǎn)又來了! Looper!
上面留下了一個(gè)問題,Looper是怎么初始化的呢,app中的通信,UI的刷新,都需要依賴handler,那么,我們就猜想,Looper在app啟動(dòng)的時(shí)候就已經(jīng)開始創(chuàng)建并初始化了,那么我們?nèi)ピ创a中找 ActivityThread main()方法 ;
public static void main(String[] args) {
````````
Looper.prepareMainLooper(); //在這里!
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop(); //還有這里
throw new RuntimeException("Main thread loop unexpectedly exited");
}
果然,在主線程啟動(dòng)的時(shí)候就已經(jīng)啟動(dòng)了Looper并調(diào)用了,prepareMainLooper()和loop();接著去looper里面看看:
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
private static void prepare(boolean quitAllowed) {
//判斷l(xiāng)ooper是否是null如果是,就創(chuàng)建,并將其存到ThreadLocal中,上面說的handler中的looper就是從ThreadLocal中取出來的;
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
Binder.clearCallingIdentity(); //這里大家不用管,我個(gè)人理解是對(duì)進(jìn)程的校驗(yàn),有知道的同學(xué)也可以留言告訴我。
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
msg.target.dispatchMessage(msg); //分發(fā)消息
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked(); //消息的回收
}
}
三個(gè)方法,prepareMainLooper()其實(shí)內(nèi)部調(diào)用了prepare(false);這個(gè)boolean參數(shù)是什么意思呢,意識(shí)就是不允許messageQueue退出,這個(gè)參數(shù)會(huì)在構(gòu)建Queue的時(shí)候傳遞進(jìn)去,因?yàn)橹骶€程的消息隊(duì)列只有在應(yīng)用退出的時(shí)候才允許退出,否則······沒有否則,消息機(jī)制都沒了,還怎么玩!
prepare()方法創(chuàng)建了一個(gè)looper,但是looper并沒有啟動(dòng),啟動(dòng)的方法是下面的loop();loop()有一個(gè)for(;;),死循環(huán),里面做的工作就是一直取消息,并處理,然后recycleUnchecked()復(fù)用。這個(gè)時(shí)候looper就啟動(dòng)起來了,只要你的應(yīng)用還在運(yùn)行,他就會(huì)一直在。looper拿到消息后會(huì)通過msg.target.dispatchMessage(msg); 將消息發(fā)出來給handler處理,這里的msg.target不就是我們發(fā)消息的時(shí)候初始化的handler嗎?(篇幅有點(diǎn)長(zhǎng),不記得可以往上翻)
繼續(xù)看,又到重點(diǎn)了
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
通過一系列判斷,來處理消息,如下:
- 判斷msg.callback是不是null,如果不是,那么就給這個(gè)callback處理,這個(gè)callback是message中的一個(gè)Runnable;Message.obtain()其實(shí)是有其他參數(shù)的方法的,其中有一個(gè)是obtain(Handler h, Runnable callback);如果你用了這個(gè),那么消息就會(huì)在你實(shí)現(xiàn)的Runnable中接收到處理的回調(diào);
- 第二個(gè)是判斷handler內(nèi)部的callback是不是null,如果不是null,就讓他去處理,這里的Callback可不是Runnable了,他是一個(gè)interface,里面定義了一個(gè)handleMessage(Message msg);方法,這個(gè)怎么實(shí)現(xiàn)呢?handler類里同樣有Handler(Callback callback)構(gòu)造方法
- 最后才輪到handler類里的方法handleMessage來處理消息。也就是我們?cè)陂_始寫的那個(gè)簡(jiǎn)單的handler使用方法。