一侮措、什么是Handler
1.Android SDK中用來(lái)處理異步消息的核心類
2.子線程可以通過(guò)Handler來(lái)通知主線程進(jìn)行UI更新
二、Handler機(jī)制的核心類
Handler:mLooper,mQueue(mLooper是從Looper中的ThreadLocal對(duì)象中獲取的泽谨,整個(gè)app中碧囊,所有的Looper對(duì)象都是保存在Looper類中的ThreadLocal靜態(tài)對(duì)象中,mQueue是根據(jù)mLooper中的mQueue賦值的)
Message
Looper:mQueue(是一個(gè)MessageQueue對(duì)象)
MessageQueue:采用單鏈表的方式存儲(chǔ)Handler需要處理的Message信息
Message:
在整個(gè)消息機(jī)制中供嚎,Message又叫Task黄娘,封裝了任務(wù)攜帶的信息和處理該任務(wù)的Handler:
1.盡管Message有public默認(rèn)的構(gòu)造方法,但是應(yīng)該通過(guò)Message.obtain()來(lái)從消息池中獲取空消息對(duì)象克滴,以節(jié)省資源逼争。
2.Message如果只需要攜帶簡(jiǎn)單的int信息,請(qǐng)優(yōu)先使用arg1和arg2來(lái)傳遞消息劝赔,這比使用Bundle更節(jié)省內(nèi)存誓焦。
Looper:輪循器
在Looper內(nèi)部有一個(gè)Thread對(duì)象,存放Looper對(duì)應(yīng)的當(dāng)前線程對(duì)象着帽。Looper內(nèi)部有一個(gè)MessageQueue隊(duì)列杂伟。用來(lái)存放消息移层。Looper輪循的時(shí)候,都是從當(dāng)前線程的Looper對(duì)象中取出MessageQueue赫粥,而當(dāng)前線程的Looper對(duì)象從ThreadLocal中獲得观话。而ThreadLocal對(duì)象則是在Looper中的一個(gè)靜態(tài)對(duì)象,是一個(gè)全局的越平。
三频蛔、原理分析
1.Looper實(shí)例創(chuàng)建和保存原理分析
MessageQueue 就是設(shè)計(jì)模式中的緩沖區(qū),它負(fù)責(zé)接收生產(chǎn)者發(fā)送過(guò)來(lái)的數(shù)據(jù)先進(jìn)先出的隊(duì)列形式秦叛,保存著所有消息晦溪。在UI Thread中通過(guò)looper 不斷從MessageQueue 取出消息在執(zhí)行任務(wù)。
Handler中獲取Looper對(duì)象:
public Handler(Callback callback, boolean async) {
//省略一些無(wú)關(guān)代碼
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;
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
在Android中书闸,所有的Looper對(duì)象都是保存在一個(gè)全局的ThreadLocal對(duì)象中尼变,Handler在線程中獲取Looper對(duì)象的時(shí)候,是調(diào)用ThreadLocal的get方法浆劲,ThreadLocal的get方法中嫌术,會(huì)優(yōu)先獲取當(dāng)前線程對(duì)象。
ThreadLocal的get方法的實(shí)現(xiàn):
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);//this是ThreadLocal<Looper>對(duì)象
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;//value即為L(zhǎng)ooper對(duì)象
return result;
}
}
return setInitialValue();
}
//ThreadLocal的getMap的源碼:
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
其實(shí)每個(gè)Thread線程中都會(huì)有一個(gè)ThreadLocalMap對(duì)象牌借。每個(gè)線程對(duì)應(yīng)的Looper實(shí)例度气,其實(shí)就是保存在每個(gè)線程實(shí)例中的ThreadLocalMap實(shí)例中
Looper 的主要工作就是維護(hù)MessageQueque中的消息隊(duì)列,它負(fù)責(zé)從MessageQueue中取出要執(zhí)行的消息任務(wù)膨报,先判斷Looper是否為null磷籍,不為null就循環(huán)狀態(tài)不斷從MessageQueue中取出消息,然后通過(guò)dispatchMessage派發(fā)出去就行處理现柠。
看下Looper的創(chuàng)建過(guò)程:
public static void loop() {
// 調(diào)用Looper.myLooper()方法院领,從ThreadLocal中取出當(dāng)前線程的Looper對(duì)象
final Looper me = myLooper();
// 如果當(dāng)前線程中的Looper對(duì)象為null,則會(huì)拋出異常
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
.....
for (;;) {
// 通過(guò)一個(gè)死循環(huán)够吩,從MessageQueue中不停的取出消息
Message msg = queue.next(); // might block
if (msg == null) {
// 由于剛創(chuàng)建的MessageQueue就開(kāi)始輪詢比然,隊(duì)列里沒(méi)有消息
// 等到Handler調(diào)用send或者post發(fā)送消息,進(jìn)而調(diào)用MessageQueue.enqueueMessage后
// 隊(duì)列里才有消息
return;
}
........
try {
// 分發(fā)信息周循,target是一個(gè)Handler對(duì)象强法,這里就是調(diào)用Handler來(lái)分發(fā)信息的。
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
.........
msg.recycleUnchecked();
}
}
每個(gè)線程只能有一個(gè)Looper對(duì)象湾笛,而且是通過(guò)ThreadLocal來(lái)存放饮怯,其他線程無(wú)法訪問(wèn)當(dāng)前的Looper。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
Looper可以讓一個(gè)普通線程具有消息循環(huán)的能力,這是源碼給出的一段示例嚎研。
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
每個(gè)application都默認(rèn)擁有一個(gè)Looper對(duì)象注釋可以看到蓖墅。在啟動(dòng)應(yīng)用程序進(jìn)程過(guò)程中,會(huì)在最后調(diào)用ActivityThread.main方法,在ActivityThread.main方法中會(huì)調(diào)用Looper.prepareMainLooper()方法初始化主線程的Looper實(shí)例置媳,所以說(shuō)UI線程默認(rèn)就有一個(gè)Looper對(duì)象于樟,可通過(guò)Looper.myLooper()方法獲取到公条。因?yàn)長(zhǎng)ooper中用來(lái)保存Looper實(shí)例的ThreadLocal是一個(gè)靜態(tài)常量拇囊,內(nèi)存中只有這一個(gè)。又根據(jù)ThreadLocal的set和get的特性靶橱,所以可以根據(jù)不同的線程取出不同的值
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
// 這里傳入false寥袭,代表MessageQueue是不允許退出的
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
/**
* Returns the application's main looper, which lives in the main thread of the application.
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
常用的方法 prepare()創(chuàng)建一個(gè)looper對(duì)象,在其他線程中想具有消息循環(huán)功能這個(gè)方法就必須調(diào)用关霸。
在Looper.prepare()方法中传黄,調(diào)用了重載方法參數(shù)傳的是true,表示是允許退出队寇,在創(chuàng)建Looper對(duì)象的時(shí)候膘掰,會(huì)將Looper所屬的當(dāng)前線程是哪個(gè)緩存在Looper實(shí)例中
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
在Looper實(shí)例中,通過(guò)調(diào)用其loop()方法佳遣,開(kāi)始循環(huán)取出消息
public static void loop() {}
2.Handler的消息發(fā)送和處理過(guò)程分析
Handler 是負(fù)責(zé)把Message壓入Queue中识埋,還負(fù)責(zé)處理Message。Handler工作必須依賴Looper才行零渐,沒(méi)有Looper對(duì)象會(huì)拋出RuntimeException異常窒舟,不管是post sendMessage 還是延時(shí)的消息發(fā)送,最終都會(huì)到enqueueMessage方法中把消息傳到緩沖區(qū)等待Looper處理诵盼。
創(chuàng)建Handler
public Handler(@Nullable Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
// 獲取當(dāng)前線程中的Looper實(shí)例
mLooper = Looper.myLooper();
// 如果當(dāng)前線程中的Looper對(duì)象為null惠豺,則拋出異常,從這里可以看出創(chuàng)建Handler對(duì)象
// 當(dāng)前線程就必須要先有Looper對(duì)象
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
// 每個(gè)Handler中使用的MessageQueue對(duì)象风宁,都是從Looper對(duì)象中取出的
// 一個(gè)線程只有一個(gè)Looper對(duì)象洁墙,可以有多少Handler對(duì)象
// 所以一個(gè)線程中的多個(gè)Handler對(duì)象是共用一個(gè)MessageQueue的
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
創(chuàng)建Message
可以直接new Message,但是有更好的方式Message.obtain戒财。因?yàn)榭梢詸z查是否可以有復(fù)用的Message用過(guò)復(fù)用避免過(guò)多的創(chuàng)建热监,銷(xiāo)毀Message對(duì)象達(dá)到優(yōu)化內(nèi)存和性能的目的
public static Message obtain(Handler h) {
// 調(diào)用重載的obtain方法
Message m = obtain();
// 并綁定創(chuàng)建Message對(duì)象的Handler對(duì)象
m.target = h;
return m;
}
public static Message obtain() {
// sPoolSync是一個(gè)Object對(duì)象,用來(lái)同步保證線程安全的
synchronized (sPoolSync) {
// sPool其實(shí)就是Handler.dispatchMessage后通過(guò)recycleUnchecked回收用以復(fù)用的Message
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
Handler內(nèi)部發(fā)送消息方法源碼解析:
(1)sendMessage方法固翰,內(nèi)部調(diào)用的是sendMessageDelayed狼纬,只不過(guò)時(shí)間傳0
public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg, 0);
}
(2)sendMessageDelayed
public final boolean sendMessageDelayed(Message msg, long delayMillis){
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
//SystemClock.uptimeMillis()表示從開(kāi)機(jī)到現(xiàn)在的毫秒數(shù)
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);
}
// 將Message與發(fā)送Message的Handler做綁定
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
// 這部分,是對(duì)Message進(jìn)行賦值骂际,將當(dāng)前的Handler對(duì)象賦值給Message.target
// 但是如果Message是采用obtain方法創(chuàng)建的疗琉,則在這個(gè)方法內(nèi)部會(huì)對(duì)target賦值
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
在Handler的enqueueMessage方法中可以看出,每個(gè)Message實(shí)例歉铝,在這里會(huì)對(duì)其target賦值Handler實(shí)例盈简,賦值的目的就是為了在Looper.loop()方法調(diào)用的時(shí)候用來(lái)在Looper.loop()方法中取出消息并且通過(guò)消息的target來(lái)將消息分發(fā)給對(duì)應(yīng)的Handler。這里的Handler是在發(fā)送消息的時(shí)候,將Message與Handler先做個(gè)綁定柠贤,即將Handler實(shí)例保存在Message中的target屬性中
注意:
System.currentTimeMillis()獲取的時(shí)間香浩,可以通過(guò)System.setCurrentTimeMillis(long)方法,進(jìn)行修改臼勉,那么在某些情況下邻吭,一旦被修改,時(shí)間間隔就不準(zhǔn)了宴霸,所以推薦使用SystemClock.uptimeMillis()囱晴,這樣就可以保證消息隊(duì)列中每個(gè)消息的時(shí)間順序是準(zhǔn)確的
MessageQueue內(nèi)部消息入隊(duì)處理
而MessageQueue的enqueueMessage,就是將消息入隊(duì)的操作瓢谢,MessageQueue是單向鏈表結(jié)構(gòu)畸写,是采用先入先出的操作來(lái)處理消息
boolean enqueueMessage(Message msg, long when) {
// 判斷消息是否為空
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
// 判斷消息是否正在使用
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
// 采用同步方法塊的方式,實(shí)現(xiàn)線程同步氓扛,保證一個(gè)隊(duì)列一次只處理一個(gè)消息的入隊(duì)
synchronized (this) {
// 判斷Looper是否有退出枯芬,這是在Looper.quit()方法中調(diào)用mQueue.quit(false);設(shè)置mQuitting為true的
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
// 回收消息,但是如果消息正在使用采郎,則會(huì)拋異常千所,不會(huì)回收
msg.recycle();
return false;
}
// 設(shè)置消息為正在使用
msg.markInUse();
// 獲取當(dāng)前時(shí)間
msg.when = when;
Message p = mMessages;
boolean needWake;
// p相當(dāng)于當(dāng)前Message的head
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
// 采用無(wú)限for循環(huán)尋找插入點(diǎn),直到找到為null的時(shí)候尉剩,因?yàn)檫@個(gè)時(shí)候p為當(dāng)前節(jié)點(diǎn)真慢,而prev為前一個(gè)節(jié)點(diǎn),找到為空的當(dāng)前節(jié)點(diǎn)理茎,然后在這個(gè)位置插入
// for循環(huán)遍歷Message隊(duì)列黑界,如果當(dāng)前要插入的msg的時(shí)間
// 大于當(dāng)前遍歷到的Message隊(duì)列中的節(jié)點(diǎn)的時(shí)間
// 則繼續(xù)遍歷,如果當(dāng)前要插入的msg的時(shí)間when小于當(dāng)前遍歷到
// 的節(jié)點(diǎn)p的時(shí)間when皂林,則將消息插入到p節(jié)點(diǎn)之前
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
// 設(shè)置需要插入的Message的下一個(gè)節(jié)點(diǎn)為null
// 設(shè)置前一個(gè)節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)為Message
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
// 這里是判斷線程是否需要被喚醒
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
這里的nativeWake朗鸠,其實(shí)是調(diào)用了frameworks/base/core/jni/android_os_MessageQueue.cpp中的
static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->wake();
}
而這里的NativeMessageQueue的wake()方法,其實(shí)就是在android_os_MessageQueue.cpp中實(shí)現(xiàn)的
void NativeMessageQueue::wake() {
mLooper->wake();
}
Looper.loop()循環(huán)處理消息并分發(fā)
MessageQueue的出隊(duì)操作础倍,其實(shí)就是next()方法烛占,返回一個(gè)Message。在線程中沟启,創(chuàng)建Looper實(shí)例之后忆家,通過(guò)調(diào)用Looper.loop()方法,循環(huán)從每個(gè)Looper實(shí)例中對(duì)應(yīng)的MessageQueue消息緩存隊(duì)列中讀取消息德迹,并且分發(fā)給Handler處理
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
// 是否退出的判斷
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
// 無(wú)限for循環(huán)
for (;;) {
if (nextPollTimeoutMillis != 0) {
// 因?yàn)橄乱粭lMessage尚未到處理時(shí)間芽卿,則會(huì)將等待過(guò)程中需要處理的內(nèi)容交給CPU
Binder.flushPendingCommands();
}
// 這里會(huì)有一個(gè)等待,在這個(gè)等待中設(shè)置了一個(gè)超時(shí)時(shí)間胳搞,即postDelayed等方式發(fā)送的延遲處理的消息卸例,其實(shí)是通過(guò)等待一定的時(shí)間再繼續(xù)執(zhí)行的方式來(lái)進(jìn)行
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// 如果當(dāng)前的msg不為空称杨,但是這個(gè)msg中的Handler為空,那么直接拿下一個(gè)消息筷转,因?yàn)檫@個(gè)消息已經(jīng)沒(méi)有Handler來(lái)進(jìn)行處理
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
//判斷當(dāng)前時(shí)間是否小于下一條要處理的消息的時(shí)間
if (now < msg.when) {
// 下一條消息尚未就緒姑原。 設(shè)置超時(shí)以在準(zhǔn)備就緒時(shí)喚醒。
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
// 取出消息呜舒,如果前一個(gè)消息不為空锭汛,則將前一個(gè)消息的指向指到當(dāng)前消息的下一個(gè)
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
// 如果前一個(gè)消息為空,則說(shuō)明當(dāng)前消息是第一個(gè)
mMessages = msg.next;
}
// 將當(dāng)前消息的指向置為null
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
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);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
而在Looper的loop()輪循器中通過(guò)MessageQueue.next()方法取出消息
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;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
// Allow overriding a threshold with a system prop. e.g.
// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
final int thresholdOverride =
SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
+ ".slow", 0);
boolean slowDeliveryDetected = false;
for (;;) {
// 調(diào)用MessageQueue的next()方法阴绢,取出下一次要處理的消息
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long traceTag = me.mTraceTag;
long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
if (thresholdOverride > 0) {
slowDispatchThresholdMs = thresholdOverride;
slowDeliveryThresholdMs = thresholdOverride;
}
final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
final boolean needStartTime = logSlowDelivery || logSlowDispatch;
final boolean needEndTime = logSlowDispatch;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
try {
// 獲取到Message對(duì)象之后店乐,調(diào)用這個(gè)消息對(duì)象中所保存的Handler對(duì)象,
//然后通過(guò)Handler的dispatchMessage方法分發(fā)消息
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logSlowDelivery) {
if (slowDeliveryDetected) {
if ((dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
slowDeliveryDetected = false;
}
} else {
if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
msg)) {
// Once we write a slow delivery log, suppress until the queue drains.
slowDeliveryDetected = true;
}
}
}
if (logSlowDispatch) {
showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
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();
}
}
在調(diào)用Looper.loop()方法處理消息的時(shí)候呻袭,會(huì)通過(guò)Message中緩存的每個(gè)消息對(duì)應(yīng)的target(也就是對(duì)應(yīng)的Handler實(shí)例)來(lái)發(fā)送給對(duì)應(yīng)的Handler,因?yàn)樵诎l(fā)送消息的時(shí)候會(huì)設(shè)置消息的target
Handler的dispatchMessage方法:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
而handleMessage就是我們?cè)谑褂肏andler的時(shí)候重寫(xiě)的那個(gè)方法
public void handleMessage(Message msg) {
}
在Handler的dispatchMessage方法中腺兴,如果實(shí)現(xiàn)了Handler的Callback接口左电,并且重寫(xiě)該接口的handleMessage方法,那么該方法一般需要返回為false页响,目的是為了執(zhí)行Handler類中的handleMessage方法篓足,如果不執(zhí)行Handler類中的handleMessage方法,則可以返回為true闰蚕,但是一般返回false
3.主線程創(chuàng)建Looper實(shí)例
在android應(yīng)用程序進(jìn)程啟動(dòng)過(guò)程中栈拖,由系統(tǒng)AMS向Zygote進(jìn)程發(fā)送啟動(dòng)應(yīng)用程序進(jìn)程的請(qǐng)求,然后在Zygote接收到該請(qǐng)求之后没陡,通過(guò)fock自身創(chuàng)建了應(yīng)用程序進(jìn)程涩哟,并且通過(guò)異常捕獲處理的方式捕獲ActivityThread.main方法,然后調(diào)用盼玄,在ActivityThread.main方法中贴彼,通過(guò)Looper.prepareMainLooper()創(chuàng)建主線程的Looper實(shí)例
Looper:
這是ActivityThread類:
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
// 創(chuàng)建Activity的Looper對(duì)象
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"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// 調(diào)用Looper循環(huán)
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
在創(chuàng)建主線程的Looper實(shí)例的時(shí)候,默認(rèn)的quitAllowed是傳了false埃儿,是不允許退出的器仗。因?yàn)閟MainLooper!=null的時(shí)候會(huì)拋出異常童番,說(shuō)明每個(gè)線程就只能有一個(gè)Looper對(duì)象精钮。
4.主線程為什么不會(huì)阻塞問(wèn)題
Looper.loop()中的for循環(huán)實(shí)際上是阻塞了整個(gè)Android检诗,而Android之所以不會(huì)阻塞劲赠,是因?yàn)锳ndroid是一個(gè)消息驅(qū)動(dòng)機(jī)制略板,在ActivityThread中有一個(gè)H類對(duì)象顷编,這個(gè)H類是Handler的子類何鸡,Android的所有事件都是通過(guò)H類接受到Message之后垢啼,然后通過(guò)Handler的handleMessage方法進(jìn)行消息處理的畴嘶。這個(gè)過(guò)程溶其,就是在ActivityThread中的main方法中會(huì)創(chuàng)建一個(gè)ActivityThread對(duì)象,然后通過(guò)ActivityThread.getHandler就可以獲得H對(duì)象策橘,也就是Handler對(duì)象炸渡,這個(gè)對(duì)象就是在ActivityThread中創(chuàng)建的一個(gè)常量對(duì)象。
5.Handler導(dǎo)致的內(nèi)存泄漏問(wèn)題
Handler導(dǎo)致內(nèi)存泄露的原因:
- (1)因?yàn)槎x的匿名內(nèi)部類丽已,會(huì)持有外部類的引用this蚌堵,可以直接調(diào)用外部類的方法和屬性。
- (2)生命周期的問(wèn)題沛婴。因?yàn)镠andler.sendMessageAtTime會(huì)調(diào)用enqueueMessage吼畏,然后msg.target=this,說(shuō)明Message會(huì)持有Handler嘁灯,而Message在傳遞過(guò)程中泻蚊,會(huì)有延時(shí)的情況,比如設(shè)置20s執(zhí)行丑婿、20分鐘執(zhí)行性雄,這樣就會(huì)出現(xiàn)Message持有了Handler,而Handler持有了Activity羹奉,但是當(dāng)Activity銷(xiāo)毀的時(shí)候秒旋,可能Message還沒(méi)處理,還在延遲等待诀拭,這樣就導(dǎo)致Activity根據(jù)JVM可達(dá)性分析算法得出Activity不能被GC回收迁筛。
下面這段代碼是一個(gè)內(nèi)部類,在Java中內(nèi)部類或者匿名內(nèi)部類都會(huì)隱私的持有外部類對(duì)象耕挨,而在Android中使用Handler的一般都是Activity细卧,這就導(dǎo)致如果handler還在執(zhí)行中而actiivty finsh掉,activity就不能被正常銷(xiāo)毀回收俗孝。進(jìn)而GC的時(shí)候就導(dǎo)致JVM不能回收Activity酒甸,有可能多次操作后就OOM了。
解決辦法:
(1)把內(nèi)部類換成static, static不會(huì)隱式持有外部對(duì)象赋铝。
由于Handler不再持有外部類對(duì)象的引用插勤,導(dǎo)致程序不允許你在Handler中操作Activity中的對(duì)象了。所以你需要在Handler中增加一個(gè)對(duì)Activity的弱引用
(2)一般Handler導(dǎo)致的內(nèi)存泄漏都是因?yàn)楦锕牵⑻幚硎钱惒降呐┘狻insh的時(shí)候消息還在處理等待狀態(tài),這個(gè)時(shí)候可以在activity finsh的時(shí)候把handler移除掉良哲,調(diào)用removeCallbacks方法移除盛卡。
(3)關(guān)閉Activity的時(shí)候停掉你的后臺(tái)線程。
如何避免在使用Handler的時(shí)候造成內(nèi)存泄漏呢筑凫?
使用顯形的引用滑沧,1.靜態(tài)內(nèi)部類并村。 2. 外部類
使用弱引用 2. WeakReference
兩者同時(shí)使用
private static class MyHandler extends Handler {
private final WeakReference<HandlerActivity2> mActivity;
public MyHandler(HandlerActivity2 activity) {
mActivity = new WeakReference<HandlerActivity2>(activity);
}
@Override
public void handleMessage(Message msg) {
System.out.println(msg);
if (mActivity.get() == null) {
return;
}
mActivity.get().todo();
}
}
使用弱引用,其實(shí)就是將對(duì)應(yīng)的Activity存在弱引用中滓技。
并且在Activity被finish的時(shí)候哩牍,還要清空MessageQueue中的正在排隊(duì)的消息。
在onDestroy中調(diào)用下面的方法清空
mHandler.removeCallbacksAndMessages(null);
Looper:
public void quit() {
mQueue.quit(false);
}
MessageQueue:
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
// 清除消息令漂,這樣消息隊(duì)列為null膝昆,就會(huì)進(jìn)入一個(gè)無(wú)限等待狀態(tài)
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// 喚醒等待
nativeWake(mPtr);
}
}
6.子線程中維護(hù)的Looper,消息隊(duì)列無(wú)消息的時(shí)候處理方法是什么叠必?有什么用荚孵?
必須要調(diào)用Looper.quit()或者quitSafely(),會(huì)把mQuitting賦值為true纬朝,會(huì)把所有的消息全部清空收叶,然后調(diào)用nativeWake(mPtr),喚醒玄组。喚醒是因?yàn)榍蹇障⒌臅r(shí)候滔驾,消息隊(duì)列為null,而Looper.loop()方法依然會(huì)在循環(huán)取出消息俄讹,就會(huì)陷入一個(gè)無(wú)限等待狀態(tài),那么就需要喚醒绕德,在next()方法中退出無(wú)限死循環(huán)患膛,直接調(diào)用return null返回一個(gè)空的null,返回空的null的時(shí)候耻蛇,在Looper.loop()方法中就會(huì)結(jié)束踪蹬。
因?yàn)橄㈥?duì)列無(wú)消息的時(shí)候,主動(dòng)調(diào)用Looper.quit()臣咖,其實(shí)就會(huì)調(diào)用MessageQueue的quit方法跃捣。
MessageQueue.quit()
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
// 將正在退出的標(biāo)志置為true,這樣在MessageQueue.next取出消息的時(shí)候夺蛇,就可以將消息返回一個(gè)null
// 而在Looper.loop()遍歷消息的時(shí)候疚漆,當(dāng)取出的消息為null的時(shí)候,就直接return
mQuitting = true;
// 清空消息隊(duì)列
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// 喚醒消息隊(duì)列刁赦,這樣做的目的是消息隊(duì)列為null的時(shí)候娶聘,MessageQueue是處于阻塞狀態(tài)
// 而這里喚醒的目的就是為了在next方法中返回一個(gè)空消息給Looper.loop()進(jìn)行處理
nativeWake(mPtr);
}
}
7.線程同步問(wèn)題
Handler機(jī)制中最主要的類MessageQueue,這個(gè)類是所有消息的存儲(chǔ)隊(duì)列甚脉,是采用優(yōu)先級(jí)隊(duì)列的方式存儲(chǔ)消息丸升,而MessageQueue類中主要的就是消息入隊(duì)和出隊(duì),分別是enqueueMessage和next方法牺氨,這兩個(gè)方法中狡耻,都是采用的synchronized關(guān)鍵字代碼塊的方式來(lái)保證消息同步的墩剖,傳入的鎖是this,即對(duì)象鎖夷狰,MessageQueue對(duì)象鎖岭皂,因?yàn)橐粋€(gè)線程對(duì)應(yīng)一個(gè)Looper,而一個(gè)Looper對(duì)應(yīng)一個(gè)MessageQueue孵淘,所以一個(gè)線程中不管多少個(gè)Handler發(fā)送和處理消息蒲障,最終都是通過(guò)synchronized同步代碼塊保證消息的入隊(duì)和出隊(duì)的同步,保證線程安全瘫证。這對(duì)于在調(diào)用同一個(gè)MessageQueue的handler對(duì)象來(lái)說(shuō)揉阎,他們是在同一個(gè)線程的,而在這個(gè)線程內(nèi)背捌,入隊(duì)和出隊(duì)都是互斥的毙籽。并且因?yàn)橐粋€(gè)線程只有一個(gè)Looper對(duì)象,一個(gè)Looper對(duì)象對(duì)應(yīng)一個(gè)MessageQueue毡庆,所以在一個(gè)線程內(nèi)坑赡,不管有多少個(gè)Handler對(duì)象一次都只會(huì)處理一個(gè)消息,因?yàn)樵贚ooper.loop()循環(huán)遍歷消息的時(shí)候么抗,每次就只能同步出去一個(gè)消息毅否。
四、四種引用
強(qiáng)引用(一般垃圾回收器不回收被強(qiáng)引用的對(duì)象)
在一般的Java程序中蝇刀,見(jiàn)到最多的就是強(qiáng)引用(strong reference)螟加。如Date date = new Date(),date就是一個(gè)對(duì)象的強(qiáng)引用吞琐。對(duì)象的強(qiáng)引用可以在程序中到處傳遞捆探。很多情況下,會(huì)同時(shí)有多個(gè)引用指向同一個(gè)對(duì)象站粟。強(qiáng)引用的存在限制了對(duì)象在內(nèi)存中的存活時(shí)間黍图。假如對(duì)象A中包含了一個(gè)對(duì)象B的強(qiáng)引用,那么一般情況下奴烙,對(duì)象B的存活時(shí)間就不會(huì)短于對(duì)象A助被。如果對(duì)象A沒(méi)有顯式的把對(duì)象B的引用設(shè)為null的話,就只有當(dāng)對(duì)象A被垃圾回收之后缸沃,對(duì)象B才不再有引用指向它恰起,才可能獲得被垃圾回收的機(jī)會(huì)。
軟引用 (內(nèi)存不足的時(shí)候趾牧,對(duì)象被回收)
軟引用(soft reference)在強(qiáng)度上弱于強(qiáng)引用检盼,通過(guò)類SoftReference來(lái)表示。它的作用是告訴垃圾回收器翘单,程序中的哪些對(duì)象是不那么重要吨枉,當(dāng)內(nèi)存不足的時(shí)候是可以被暫時(shí)回收的蹦渣。當(dāng)JVM中的內(nèi)存不足的時(shí)候,垃圾回收器會(huì)釋放那些只被軟引用所指向的對(duì)象貌亭。如果全部釋放完這些對(duì)象之后柬唯,內(nèi)存還不足,才會(huì)拋出OutOfMemory錯(cuò)誤圃庭。軟引用非常適合于創(chuàng)建緩存锄奢。當(dāng)系統(tǒng)內(nèi)存不足的時(shí)候,緩存中的內(nèi)容是可以被釋放的剧腻。
弱引用 (回收器只要發(fā)現(xiàn)一個(gè)對(duì)象的引用是全部是弱引用拘央,就會(huì)回收此對(duì)象、釋放內(nèi)存)
弱引用(weak reference)在強(qiáng)度上弱于軟引用书在,通過(guò)類WeakReference來(lái)表示灰伟。它的作用是引用一個(gè)對(duì)象,但是并不阻止該對(duì)象被回收儒旬。如果使用一個(gè)強(qiáng)引用的話栏账,只要該引用存在,那么被引用的對(duì)象是不能被回收的栈源。弱引用則沒(méi)有這個(gè)問(wèn)題挡爵。在垃圾回收器運(yùn)行的時(shí)候,如果一個(gè)對(duì)象的所有引用都是弱引用的話甚垦,該對(duì)象會(huì)被回收了讨。
Handler中使用弱引用來(lái)保存Activity對(duì)象,就是因?yàn)锳ctivity對(duì)象如果在Handler執(zhí)行過(guò)程中被銷(xiāo)毀回收制轰,那么如果不使用弱引用,這時(shí)Activity在Handler中就是屬于強(qiáng)引用胞谭,則不會(huì)被回收垃杖,這樣就會(huì)造成了內(nèi)存泄漏,而使用弱引用的話丈屹,就不會(huì)阻止Handler中的Activity對(duì)象被回收调俘。
五、Handler.postDelayed實(shí)現(xiàn)原理
這部分是對(duì)上面Handler原理的加以說(shuō)明
1.Handler.postDelayed方法其方法內(nèi)部旺垒,調(diào)用的是Handler的sendMessageDelayed方法:
public final boolean postDelayed(Runnable r, long delayMillis){
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
2.看下sendMessageDelayed源碼:
public final boolean sendMessageDelayed(Message msg, long delayMillis){
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
從這個(gè)方法中可以看出彩库,延遲時(shí)間其實(shí)是在SystemClock.uptimeMillis()這個(gè)時(shí)間的基礎(chǔ)上,加上延遲時(shí)間的先蒋,SystemClock.uptimeMillis()是從系統(tǒng)開(kāi)機(jī)啟動(dòng)到現(xiàn)在的時(shí)間骇钦,而且不包括休眠時(shí)間,因此這是一個(gè)相對(duì)時(shí)間竞漾。
用這樣的方式眯搭,而不是用當(dāng)前時(shí)間窥翩,主要也是因?yàn)镠andler會(huì)受到阻塞、掛起狀態(tài)鳞仙、睡眠等寇蚊,這些時(shí)候是不應(yīng)該執(zhí)行的。
3.sendMessageAtTime
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);
}
這個(gè)方法做的工作棍好,就是將Message消息存放到MessageQueue中仗岸,但是并沒(méi)有做延遲存放的操作。存放的這個(gè)過(guò)程傳入uptimeMillis時(shí)間借笙,主要是為了對(duì)所有的message做排序扒怖,按需要執(zhí)行的順序?qū)essage排序放好,以便在next方法中順序取出提澎。
上面三個(gè)步驟是存放Message的姚垃,但是并沒(méi)有做任何延遲的處理,那么延遲的操作則不是在存的時(shí)候進(jìn)行的盼忌,那么只有可能是在取message的時(shí)候做了延遲處理
而上面關(guān)于Handler的消息處理分發(fā)部分的Looper.loop()的源碼解析可以看出积糯,loop方法內(nèi)部,并沒(méi)有等待或者阻塞等操作谦纱,而只有MessageQueue的next方法有一個(gè)注釋:可能會(huì)阻塞看成,那么看MessageQueue的next方法
4.MessageQueue的next()方法
在MessageQueue中,有一個(gè)是否阻塞的標(biāo)志位跨嘉,這個(gè)是用來(lái)判斷是否在pollOnce()的時(shí)候被阻塞等待了川慌。
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
// 是否退出的判斷
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
// 無(wú)限for循環(huán)
for (;;) {
if (nextPollTimeoutMillis != 0) {
// 因?yàn)橄乱粭lMessage尚未到處理時(shí)間,則會(huì)將等待過(guò)程中需要處理的內(nèi)容交給CPU
Binder.flushPendingCommands();
}
// 這里會(huì)有一個(gè)等待祠乃,在這個(gè)等待中設(shè)置了一個(gè)超時(shí)時(shí)間梦重,即postDelayed等方式發(fā)送的延遲處理的消息,其實(shí)是通過(guò)等待一定的時(shí)間再繼續(xù)執(zhí)行的方式來(lái)進(jìn)行
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// 如果當(dāng)前的msg不為空亮瓷,但是這個(gè)msg中的Handler為空琴拧,那么直接拿下一個(gè)消息,因?yàn)檫@個(gè)消息已經(jīng)沒(méi)有Handler來(lái)進(jìn)行處理
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
//判斷當(dāng)前時(shí)間是否小于下一條要處理的消息的時(shí)間
if (now < msg.when) {
// 下一條消息尚未就緒嘱支。 設(shè)置超時(shí)以在準(zhǔn)備就緒時(shí)喚醒蚓胸。
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
// 取出消息,如果前一個(gè)消息不為空除师,則將前一個(gè)消息的指向指到當(dāng)前消息的下一個(gè)
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
// 如果前一個(gè)消息為空沛膳,則說(shuō)明當(dāng)前消息是第一個(gè)
mMessages = msg.next;
}
// 將當(dāng)前消息的指向置為null
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
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);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
在這里重復(fù)一遍關(guān)于 MessageQueue.next()方法
當(dāng)nextPollTimeoutMillis是大于0的時(shí)候,那么下一次循環(huán)的時(shí)候會(huì)調(diào)用nativePollOnce方法汛聚,讓隊(duì)列阻塞锹安。但是如果當(dāng)前的隊(duì)列是阻塞的,這個(gè)時(shí)候加入了一個(gè)不是延遲發(fā)送的message的時(shí)候,就會(huì)將這個(gè)message加入隊(duì)首八毯,然后主動(dòng)喚醒隊(duì)列搓侄,處理這個(gè)消息
六、自定義手寫(xiě)Handler:
Handler實(shí)際上就是一個(gè)生產(chǎn)者與消費(fèi)者模式话速。
public class Handler {
private MessageQueue mQueue;
public Handler() {
Looper mLooper = Looper.myLooper();
mQueue = mLooper.mQueue;
}
/**
* 發(fā)送消息讶踪,加入隊(duì)列
* @param msg
*/
public void sendMessage(Message msg){
msg.target = this;
// 傳入消息
mQueue.enqueueMessage(msg);
}
/**
* 處理消息
* @param msg
*/
public void handleMessage(Message msg){
}
/**
* 分發(fā)消息
* @param msg
*/
public void dispatchMessage(Message msg){
handleMessage(msg);
}
}
Message類:
public class Message {
// Message在使用Handler發(fā)送消息的時(shí)候,將Handler賦值給對(duì)應(yīng)的Message
//用于在Looper.loop()獲取消息之后泊交,通過(guò)Handler實(shí)例分發(fā)消息
Handler target;
public Object obj;
public int what;
public Message() {
}
@Override
public String toString() {
return obj.toString();
}
}
MessageQueue類:
public class MessageQueue {
private Message[] items;
// 入隊(duì)和出隊(duì)的索引位置
private int putIndex;
private int takeIndex;
// 計(jì)數(shù)器
private int count;
private Lock lock;
private Condition notEmpty;
private Condition notFull;
public MessageQueue() {
items = new Message[50];
// 可重入鎖
lock = new ReentrantLock();
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
/**
* 取出消息
*
* @return
*/
public Message next() {
Message msg = null;
try {
lock.lock();
// 如果消息隊(duì)列為null乳讥,則等待新消息的入隊(duì)
while (count == 0) {
notEmpty.await();
}
msg = items[takeIndex];
items[takeIndex] = null;
takeIndex = (++takeIndex == items.length) ? 0 : takeIndex;
count--;
// 已經(jīng)消費(fèi)了一個(gè)消息,可以繼續(xù)入隊(duì)
notFull.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
return msg;
}
/**
* 加入隊(duì)列
*
* @param msg
*/
public void enqueueMessage(Message msg) {
// 使用while循環(huán)廓俭,這樣的話云石,就可以避免不需要喚醒的子線程繼續(xù)等待。因?yàn)槭菃拘蚜巳垦衅梗锌赡軉拘蚜瞬恍枰粏拘训淖泳€程
// 但是如果是使用if汹忠,則只會(huì)等待一次
try {
lock.lock();
// 如果消息隊(duì)列已滿,則等待
while (count == 50) {
notFull.await();
}
items[putIndex] = msg;
putIndex = (++putIndex == items.length) ? 0 : putIndex;
count++;
// 如果消息隊(duì)列不為null雹熬,則可以取出消息
notEmpty.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
Looper類:
public class Looper {
public MessageQueue mQueue;
static ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>();
private Looper(){
mQueue = new MessageQueue();
}
/**
* 初始化Looper對(duì)象
*/
public static void prepare(){
if (sThreadLocal.get() != null){
throw new RuntimeException("一個(gè)線程只能有一個(gè)looper");
}
sThreadLocal.set(new Looper());
}
/**
* 獲取當(dāng)前線程的Looper對(duì)象
* @return
*/
public static Looper myLooper(){
return sThreadLocal.get();
}
public static void loop(){
Looper me = myLooper();
if (me == null){
throw new RuntimeException("當(dāng)前線程無(wú)Looper對(duì)象");
}
MessageQueue messageQueue = me.mQueue;
for (;;){
Message msg = messageQueue.next();
if (msg != null){
msg.target.dispatchMessage(msg);
}
}
}
}
七宽菜、new Handler()兩種方式
private Handler mHandler1 = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
return false;
}
});
private Handler mHandler2 = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
一種是通過(guò)Handler的無(wú)參構(gòu)造器來(lái)創(chuàng)建,一種是通過(guò)有參構(gòu)造器來(lái)創(chuàng)建竿报。
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
在Handler中铅乡,是在dispatchMessage中來(lái)分發(fā)消息的,而這里的分發(fā)消息烈菌,是首先判斷mCallback是否為空來(lái)執(zhí)行的阵幸。
為什么使用Handler消息機(jī)制可以跨進(jìn)程?
因?yàn)樵谕粋€(gè)進(jìn)程里芽世,內(nèi)存是共享的挚赊,Looper對(duì)象創(chuàng)建在主線程,Handler對(duì)象創(chuàng)建在主線程济瓢,然后再子線程中使用這個(gè)Handler對(duì)象發(fā)送消息咬腕,因?yàn)镸essageQueue是在Looper對(duì)象中的,而Looper對(duì)象是在主線程中創(chuàng)建的葬荷,而且Handler對(duì)象是在主線程中創(chuàng)建的,所以Handler對(duì)象的handleMessage方法是在主線程中執(zhí)行的纽帖,又因?yàn)長(zhǎng)ooper.loop()是在主線程中執(zhí)行的宠漩,每次都是輪循MessageQueue獲取Message,然后通過(guò)主線程的Handler對(duì)象的dispatchMessage分發(fā)懊直,發(fā)送到handleMessage扒吁。
八、Handler內(nèi)存泄露的原因室囊?為什么其他的內(nèi)部類沒(méi)有說(shuō)過(guò)這個(gè)問(wèn)題雕崩?
(1)因?yàn)槎x的匿名內(nèi)部類魁索,會(huì)持有外部類的引用this,可以直接調(diào)用外部類的方法和屬性盼铁。
(2)生命周期的問(wèn)題粗蔚。因?yàn)镠andler.sendMessageAtTime會(huì)調(diào)用enqueueMessage,然后msg.target=this饶火,說(shuō)明Message會(huì)持有Handler鹏控,而Message在傳遞過(guò)程中,會(huì)有延時(shí)的情況肤寝,比如設(shè)置20s執(zhí)行当辐、20分鐘執(zhí)行,這樣就會(huì)出現(xiàn)Message持有了Handler鲤看,而Handler持有了Activity缘揪,但是當(dāng)Activity銷(xiāo)毀的時(shí)候,可能Message還沒(méi)處理义桂,還在延遲等待找筝,這樣就導(dǎo)致Activity根據(jù)JVM可達(dá)性分析算法得出Activity不能被GC回收。
http://www.reibang.com/p/e6877401a0e2
九澡刹、Handler#runWithScissors
在創(chuàng)建WMS對(duì)象的時(shí)候呻征,WMS的main方法中就通過(guò)調(diào)用DisplayThread.getHandler().runWithScissors()方法創(chuàng)建。
WMS的main方法是在SystemServer進(jìn)程的主線程調(diào)用的罢浇,然后在調(diào)用WMS的main方法的時(shí)候陆赋,通過(guò)DisplayThread這個(gè)HandlerThread,實(shí)現(xiàn)異步處理嚷闭,而這里的異步處理攒岛,其實(shí)是通過(guò)跨線程的一個(gè)同步,即通過(guò)DisplayThread中的Handler對(duì)象胞锰,調(diào)用runWithScissors方法灾锯,該方法其實(shí)是可以實(shí)現(xiàn)發(fā)送消息等待消息處理完成之后再繼續(xù)執(zhí)行runWithScissors方法調(diào)用位置之后的代碼,即等待消息處理完之后再進(jìn)行return WMS對(duì)象嗅榕。
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm) {
return main(context, im, showBootMsgs, onlyCore, policy, atm,
SurfaceControl.Transaction::new);
}
@VisibleForTesting
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm, TransactionFactory transactionFactory) {
// 這里其實(shí)就是在DisplayThread線程處理WMS的初始化
DisplayThread.getHandler().runWithScissors(() ->
sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
atm, transactionFactory), 0);
return sInstance;
}
1.Handler#runWithScissors
根據(jù)上面的調(diào)用顺饮,上面的runWithScissors傳入的就是一個(gè)Runnable實(shí)例,只不過(guò)是采用了lambda表達(dá)式的做法凌那,所以Runnable的run()方法的方法體是就是:
sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy, atm, transactionFactory), 0);
public final boolean runWithScissors(@NonNull Runnable r, long timeout) {
if (r == null) {
throw new IllegalArgumentException("runnable must not be null");
}
if (timeout < 0) {
throw new IllegalArgumentException("timeout must be non-negative");
}
// 如果調(diào)用runWithScissors方法的線程是與消息處理線程在同一個(gè)線程
// 則直接執(zhí)行Runnable的run方法兼雄。
if (Looper.myLooper() == mLooper) {
r.run();
return true;
}
// 如果調(diào)用runWithScissors方法的線程與消息處理線程不是同一個(gè),則創(chuàng)建一個(gè)BlockingRunnable
BlockingRunnable br = new BlockingRunnable(r);
// 并且調(diào)用BlockingRunnable.postAndWait方法
// 這里的返回值會(huì)先等待帽蝶,等待DisplayThread線程中的Handler處理完
// 消息之后赦肋,然后喚醒BlockingRunnable
// 該Handler處理消息是在DisplayThread線程,而B(niǎo)lockingRunnable
// 而B(niǎo)lockingRunnable調(diào)用wait并不會(huì)讓DisplayThread線程中的
// Handler等待佃乘,Handler依然會(huì)處理消息囱井,處理消息其實(shí)就是調(diào)用了
// BlockingRunnable.run()方法,當(dāng)BlockingRunnable.run()執(zhí)行完成
// 就會(huì)調(diào)用notifyAll喚醒BlockingRunnable趣避,執(zhí)行postAndWait的return
return br.postAndWait(this, timeout);
}
2.BlockingRunnable
private static final class BlockingRunnable implements Runnable {
private final Runnable mTask;
private boolean mDone;
public BlockingRunnable(Runnable task) {
mTask = task;
}
@Override
public void run() {
try {
// 這個(gè)mTask其實(shí)就是runWithScissors中傳入的Runnable對(duì)象
// BlockingRunnable的run方法的執(zhí)行庞呕,其實(shí)就是需要Handler遍歷到消息處理的時(shí)候
// 然后處理這個(gè)BlockingRunnable消息,在處理BlockingRunnable消息
// 的時(shí)候鹅巍,就會(huì)處理runWithScissors的參數(shù)中的Runnable這個(gè)mTask
// 處理完成之后千扶,就會(huì)調(diào)用notifyAll喚醒等待線程,然后執(zhí)行postAndWait的return
// 因?yàn)锽lockingRunnable的run方法是由Handler處理消息
// 這個(gè)消息的處理與BlockingRunnable是在不同的線程
// 所以BlockingRunnable等待的時(shí)候骆捧,其run方法是可以由handler消息處理
mTask.run();
} finally {
synchronized (this) {
mDone = true;
notifyAll();
}
}
}
public boolean postAndWait(Handler handler, long timeout) {
// 調(diào)用postAndWait的時(shí)候澎羞,先調(diào)用handler對(duì)象的post將消息發(fā)送出
// 如果入隊(duì)成功,則為true敛苇,則開(kāi)始阻塞
if (!handler.post(this)) {
return false;
}
// 在上面的方法調(diào)用中妆绞,timeout=0,則阻塞枫攀。
synchronized (this) {
if (timeout > 0) {
final long expirationTime = SystemClock.uptimeMillis() + timeout;
// 如果mDone為false的時(shí)候括饶,則會(huì)等待,只有為true的時(shí)候来涨,會(huì)執(zhí)行
while (!mDone) {
long delay = expirationTime - SystemClock.uptimeMillis();
if (delay <= 0) {
return false; // timeout
}
try {
wait(delay);
} catch (InterruptedException ex) {
}
}
} else {
while (!mDone) {
try {
wait();
} catch (InterruptedException ex) {
}
}
}
}
return true;
}
}