Handler 是用來做什么的述吸?
總的來說剩彬,Handler可以跨線程發(fā)送Message
對應(yīng)用層來說阿纤,Android不允許主線程以外的線程更新UI凳厢,所以需要借助Handler來更新UI
對Framework來說,AMS通過Binder跨進(jìn)程悟耘,發(fā)送消息到ApplicationThread落蝙,ApplicationThread
向H
(繼承自Handler)發(fā)送消息,H收到消息后再ActivityThread中處理
Handler Looper MessageQueue Message 四者關(guān)系暂幼?
![](https://lh3.googleusercontent.com/-kQPf6BFtjyQ/WPYIkvhNg8I/AAAAAAAAEAQ/SvDIZZJ_nRk/I/14925176027196.jpg)
一次完整的Handler使用流程是怎么樣的筏勒?
![使用流程](https://lh3.googleusercontent.com/-uweFv-yfo3U/WPYIXz1HrWI/AAAAAAAAEAI/-rpcCf1I7AE/I/14924418735047.jpg)
一、Looper.prepare( ):
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//設(shè)置Looper到ThreadLocal
sThreadLocal.set(new Looper(quitAllowed));
}
二旺嬉、在消費線程實例化Handler管行,Handler在ThreadLocal中放置屬于此線程的Looper。設(shè)置將來獲得Message的方法(復(fù)寫dispatchMessage()
方法邪媳,或者通過接口回調(diào))
Handler 所有的構(gòu)造方法:
![Handler 所有的構(gòu)造方法](https://lh3.googleusercontent.com/-23Cepdc4AT0/WPYIYH6LGdI/AAAAAAAAEAM/hZYhf09cREs/I/14924252597967.jpg)
Handler獲得Looper有兩種途徑:
- 構(gòu)造方法
-
Looper.myLooper()
的靜態(tài)方法
public Handler(Callback callback, boolean async) {
//Looper從ThreadLocal獲得該線程的mLooper
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
//獲得該線程的MessageQueue
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
三捐顷、在另一個線程,用Handler的引用雨效,發(fā)送Message
//最終會調(diào)用該方法
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
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) {
//在Message中保存該Handler的引用
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
//插入一條消息到單鏈表MessageQueue
return queue.enqueueMessage(msg, uptimeMillis);
}
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
//重復(fù)生產(chǎn)了多條相同的Message而沒有被消費掉
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
//已經(jīng)沒有Looper啦迅涮,插不進(jìn)去了
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
//標(biāo)記正在使用
msg.markInUse();
msg.when = when;
//哨兵
Message p = mMessages;
boolean needWake;
//此次傳入的msg為頭
if (p == null || when == 0 || when < p.when) {
//設(shè)置哨兵
msg.next = p;
//mMessage更新為該msg
mMessages = msg;
needWake = mBlocked;
} else {
needWake = mBlocked && p.target == null && msg.isAsynchronous();
//prev為msg的前一個
Message prev;
for (;;) {
//既然p不為空,p即使msg的前一個
prev = p;
//更新p為p的下一個
p = p.next;
//p的下一個為空徽龟,意味著到達(dá)尾部叮姑,跳出
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
//msg的下一個為p,p為空
msg.next = p;
//插入到末尾
prev.next = msg;
}
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
四据悔、Looper.loop()
public static void loop() {
//獲得屬于該線程的Looper
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//獲得MessageQueue
final MessageQueue queue = me.mQueue;
for (;;) {
//循環(huán)去獲取下一條消息
Message msg = queue.next();
//queue.next()返回null <==> 該線程的looper退出了
if (msg == null) {
return;
}
try {
//msg.target返回Handler传透,Handler.dispatchMessage(msg)完成消息的傳遞
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
}
}
Message next() {
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1;
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//沒有消息的話線程進(jìn)入休眠
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
nextPollTimeoutMillis = -1;
}
if (mQuitting) {
dispose();
return null;
}
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
pendingIdleHandlerCount = 0;
nextPollTimeoutMillis = 0;
}
}
Looper到底保存在哪里的?
一個線程一般私有三種類型的數(shù)據(jù):
- 棧
- Thread Local Storage
- 寄存器
在一個線程調(diào)用Looper.prepare()
后屠尊,會實例化一個Looper對象,保存在Thread Local Storage中耕拷。 Handler可以從TLS中獲得Looper的引用讼昆,這樣就可以把Thread和Looper形成一一對應(yīng)的關(guān)系
Handler如何循環(huán)?
調(diào)用Looper.loop( )后骚烧,會進(jìn)入一個永真循環(huán)浸赫,去調(diào)用queue.next( )
而queue.next( )又是一個永真循環(huán),不斷查詢是否有新的消息
循環(huán)在什么時候退出赃绊?
對于Looper.loop()
中的循環(huán)既峡,當(dāng)且僅當(dāng)queue.next()
返回null時退出
對于queue.next()
中的循環(huán),當(dāng)且僅當(dāng)mQuitting為真時退出
queue.next()
什么時候會返回null呢碧查?
查看源碼我們發(fā)現(xiàn)有兩處return null
if (ptr == 0) {
return null;
}
if (mQuitting) {
dispose();
return null;
}
對于第一處:
當(dāng)一個線程的Looper已經(jīng)退出运敢,并且所有的消息都處理了校仑,如果再重啟這個Looper,就會使得ptr==0
為真
意思就是一個線程處理了所有事件传惠,手動退出Looper迄沫。以后就算再重新調(diào)用Looper.loop()
,也是不能正常收到事件的
對于第二處:
當(dāng)mQuitting為真會進(jìn)入該段代碼
那什么情況下mQuitting會為真呢
在Looper.quit( ):
public void quit() {
mQueue.quit(false);
}
MessageQueue.quit():
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
可以發(fā)現(xiàn)卦方,當(dāng)且僅當(dāng)我們調(diào)用了MessageQueue.quit()
羊瘩,mQuitting
為真,MessageQueue.next()
返回null盼砍,跳出循環(huán)尘吗,進(jìn)而調(diào)到next()
方法的Looper.loop()
方法也跳出循環(huán)
也就是說,只有我們調(diào)用了Looper.quit()后浇坐,循環(huán)才會停止
同時我們注意到了throw new IllegalStateException("Main thread not allowed to quit.");
這個異常睬捶,也就是說我們不可能主動退出主線程的Looper,不能手動停止主線程的消息循環(huán)
主線程的Handler在哪實例化的吗跋?Looper又在哪里調(diào)用prepare( )和loop( )的侧戴?
在ActivityThread中有以下代碼
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
EventLogger.setReporter(new EventLoggingReporter());
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
//準(zhǔn)備主線程的Looper
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
//創(chuàng)建ApplicationThread,即開啟Binder跌宛,接收AMS消息
thread.attach(false);
//實例化Handler酗宋,此Handler接收ApplicationThread的消息
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
//Looper.loop( )
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
可以看見我們調(diào)用Looper.prepareMainLooper()
來準(zhǔn)備我們主線程的Looper
該方法會檢查主線程的Looper是否已經(jīng)創(chuàng)建過了,如果創(chuàng)建過了疆拘,就拋出異常
并且設(shè)置主線程的Looper是不允許退出的蜕猫,而且,只有主線程的Looper能夠有此殊榮
主線程的Handler類名叫H哎迄,是ActivityThread類的內(nèi)部類
handleMessage(Message msg)
方法負(fù)責(zé)分發(fā)事件回右,這個方法在ApplicationThread
被sendMessage()
方法調(diào)用,ApplicationThread
繼承自Binder
漱挚,接收來自AMS的IPC消息