Android移除Message的方法分享
退出Looper循環(huán)移除Message的兩種方式
大家都知道,消息機(jī)制在Android系統(tǒng)運(yùn)行中扮演著重要的角色,通過(guò)消息發(fā)送、添加消息隊(duì)列、分發(fā)等一整個(gè)流程驅(qū)動(dòng)Android的運(yùn)行。
主線程是在ActivityThread.main()中調(diào)用了Looper.loop(),開(kāi)啟消息循環(huán)遍歷執(zhí)行的,這個(gè)消息循環(huán)可以退出嗎,接下來(lái)我們仔細(xì)研究下;
上源碼:
void quit(boolean safe) {
//1.不允許退出就拋出異常
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
//2.
mQuitting = true;
if (safe) {
//3.安全退出
removeAllFutureMessagesLocked();
} else {
//4.非安全退出
removeAllMessagesLocked();
}
nativeWake(mPtr);
}
}
1.對(duì)于主線程而言,mQuitAllowed的值是false,也就是說(shuō)主線程的Looper循環(huán)不允許手動(dòng)調(diào)用quit()退出,否則就拋出異常;
2.將退出標(biāo)識(shí)mQuitting置為true,這樣當(dāng)從消息隊(duì)列中取消息時(shí),會(huì)先判斷下這個(gè)標(biāo)識(shí)mQuitting是否為true,是就會(huì)經(jīng)過(guò)調(diào)用鏈一步步退出Looper消息循環(huán);
3.安全的退出Looper開(kāi)啟的消息循環(huán),深入下removeAllFutureMessagesLocked()看下:
private void removeAllFutureMessagesLocked() {
final long now = SystemClock.uptimeMillis();
Message p = mMessages;
if (p != null) {
//1.
if (p.when > now) {
removeAllMessagesLocked();
} else {
Message n;
for (;;) {
n = p.next;
if (n == null) {
return;
}
if (n.when > now) {
break;
}
p = n;
}
p.next = null;
do {
p = n;
n = p.next;
p.recycleUnchecked();
} while (n != null);
}
}
}
- 首先如果消息隊(duì)列隊(duì)頭的消息的執(zhí)行
時(shí)間戳when大于當(dāng)前時(shí)間,則直接調(diào)用removeAllMessagesLocked()方法移除所有的消息 ,這個(gè)方法之后會(huì)講解; - 上面條件不滿足,就不斷的遍歷消息隊(duì)列,直到找出
執(zhí)行時(shí)間戳大于當(dāng)前時(shí)間的消息,然后通過(guò)do-while()循環(huán),將該消息及之后的消息全部進(jìn)行回收處理,放入到我們之前講解的對(duì)象池;
4.非安全的退出是直接調(diào)用了removeAllMessagesLocked()方法,我們深入看下:
private void removeAllMessagesLocked() {
Message p = mMessages;
while (p != null) {
Message n = p.next;
p.recycleUnchecked();
p = n;
}
mMessages = null;
}
可以看到這種移除方法大殺特殺,不會(huì)去比較消息執(zhí)行的時(shí)間戳啥的,直接全部干翻回收到消息對(duì)象池,簡(jiǎn)單粗暴。
這里對(duì)于非安全和安全退出Looper循環(huán)做個(gè)總結(jié):
安全退出Looper循環(huán)只會(huì)移除回收大于當(dāng)前時(shí)間戳的消息,而不大于當(dāng)前時(shí)間戳的消息都可以保證正常執(zhí)行;而非安全的退出比較粗暴,直接清空回收整個(gè)消息隊(duì)列。這兩種情況大家根據(jù)需要選擇性的使用。
removeXXXMessages()移除指定的消息

可以看到移除消息的方法一大堆,比如通過(guò)指定Message的what、obj、callback等信息移除指定Message,這里我們就以removeCallbacksAndMessages()舉例。
removeCallbacksAndMessages()方法大家應(yīng)該很梳理,是我們?cè)谀硞€(gè)界面中使用Handler發(fā)送消息時(shí),避免發(fā)生內(nèi)存泄漏的一種方式,接下來(lái)我們深入分析下:
void removeCallbacksAndMessages(Handler h, Object object) {
//...
synchronized (this) {
Message p = mMessages;
//1.從頭移除消息
while (p != null && p.target == h
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
//2. 從中間移除消息
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && (object == null || n.obj == object)) {
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}
如果這個(gè)方法傳入的object不為null,就會(huì)移除指定的Message,如果指定為null,就會(huì)移除傳入的Handler發(fā)送的所有消息。
上面的源碼中可以看到,移除Message分為兩個(gè)部分,為什么要這么做呢?
假設(shè)消息隊(duì)列中存在下面一系列消息集合:

如果Message1滿足移除條件,那么直接回收這條消息,并將消息隊(duì)列的隊(duì)頭指針指向下一個(gè)消息即可mMessages = mMessages.next,對(duì)應(yīng)上面源碼中前半部分移除消息的邏輯。
但假設(shè)Message1不滿足移除條件,Message2滿足移除條件,這樣移除就不是直接將消息隊(duì)列的隊(duì)頭指針指向next即下一個(gè)Message就能簡(jiǎn)單解決的。
正確的做法是:先要保存Message1,然后通過(guò)Message2.next獲取到Message3的引用保存起來(lái),最后將Message1.next指向上面保存的Message3引用。這部分就對(duì)應(yīng)上面源碼中后半部分移除消息的邏輯。
總結(jié)
本篇文章主要是對(duì)MessageQueue提供的各種移除Message的方法做了一個(gè)簡(jiǎn)單的介紹,方法很多主要分為兩種:移除指定標(biāo)識(shí)的Handler發(fā)送的Message和移除所有Handler發(fā)送的Message。
到此這篇關(guān)于Android移除Message的方法分享的文章就介紹到這了,更多相關(guān)Android移除Message內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android UI實(shí)現(xiàn)多行文本折疊展開(kāi)效果
這篇文章主要為大家詳細(xì)介紹了Android UI實(shí)現(xiàn)多行文本折疊展開(kāi)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10
android studio實(shí)現(xiàn)簡(jiǎn)單的計(jì)算器功能
這篇文章主要為大家詳細(xì)介紹了android studio實(shí)現(xiàn)簡(jiǎn)單的計(jì)算器功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05
Android 二維碼 生成和識(shí)別二維碼 附源碼下載
這篇文章主要介紹了Android 生成和識(shí)別二維碼的方法,提供源碼下載,需要的朋友可以參考下。2016-06-06
Android編程ProgressBar自定義樣式之動(dòng)畫(huà)模式實(shí)現(xiàn)方法
這篇文章主要介紹了Android編程ProgressBar自定義樣式之動(dòng)畫(huà)模式實(shí)現(xiàn)方法,涉及Android動(dòng)畫(huà)模式的布局技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-10-10
Android使alertDialog.builder不會(huì)點(diǎn)擊外面和按返回鍵消失的方法
本篇文章主要介紹了Android使alertDialog.builder不會(huì)點(diǎn)擊外面和按返回鍵消失的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-01-01
Android實(shí)現(xiàn)支付寶手勢(shì)密碼功能
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)支付寶手勢(shì)密碼功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03
Android Camera2實(shí)現(xiàn)最簡(jiǎn)單的預(yù)覽框顯示
這篇文章主要為大家詳細(xì)介紹了Android Camera2實(shí)現(xiàn)最簡(jiǎn)單的預(yù)覽框顯示,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
Android實(shí)現(xiàn)View滑動(dòng)效果的6種方法
這篇文章主要介紹了Android實(shí)現(xiàn)View滑動(dòng)的6種方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-03-03
android整數(shù)二分模板徹底解決邊界問(wèn)題
這篇文章主要介紹了android整數(shù)二分模板徹底解決邊界問(wèn)題,主要利用android整數(shù)二分模板解決邊界問(wèn)題,需要的朋友可以參考一下,希望對(duì)你有所幫助2021-12-12

