網(wǎng)站首頁(yè) 編程語言 正文
退出Looper循環(huán)移除Message的兩種方式
大家都知道,消息機(jī)制在Android系統(tǒng)運(yùn)行中扮演著重要的角色,通過消息發(fā)送、添加消息隊(duì)列、分發(fā)等一整個(gè)流程驅(qū)動(dòng)Android的運(yùn)行。
主線程是在ActivityThread.main()
中調(diào)用了Looper.loop()
,開啟消息循環(huán)遍歷執(zhí)行的,這個(gè)消息循環(huán)可以退出嗎,接下來我們仔細(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,也就是說主線程的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)過調(diào)用鏈一步步退出Looper
消息循環(huán);
3.安全的退出Looper
開啟的消息循環(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í)間的消息
,然后通過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()移除指定的消息
可以看到移除消息的方法一大堆,比如通過指定Message
的what
、obj
、callback
等信息移除指定Message
,這里我們就以removeCallbacksAndMessages()
舉例。
removeCallbacksAndMessages()
方法大家應(yīng)該很梳理,是我們?cè)谀硞€(gè)界面中使用Handler
發(fā)送消息時(shí),避免發(fā)生內(nè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
,然后通過Message2.next
獲取到Message3
的引用保存起來,最后將Message1.next
指向上面保存的Message3
引用。這部分就對(duì)應(yīng)上面源碼中后半部分移除消息的邏輯。
總結(jié)
本篇文章主要是對(duì)MessageQueue
提供的各種移除Message
的方法做了一個(gè)簡(jiǎn)單的介紹,方法很多主要分為兩種:移除指定標(biāo)識(shí)的Handler
發(fā)送的Message
和移除所有Handler
發(fā)送的Message
。
原文鏈接:https://juejin.cn/post/7153056511831310366
相關(guān)推薦
- 2022-07-15 ASP.NET?Core獲取正確查詢字符串參數(shù)示例_實(shí)用技巧
- 2022-06-25 C#設(shè)計(jì)模式之適配器模式與裝飾器模式的實(shí)現(xiàn)_C#教程
- 2022-09-21 python?Flask框架之HTTP請(qǐng)求詳解_python
- 2022-11-30 Python?fire模塊(最簡(jiǎn)化命令行生成工具)的使用教程詳解_python
- 2024-01-11 org.apache.commons.collections.MapUtils Map集合工具類
- 2022-06-29 C語言超詳細(xì)講解指針的概念與使用_C 語言
- 2022-05-25 Flutter實(shí)現(xiàn)掃二維碼功能_Android
- 2022-07-18 MVC與MVVM的區(qū)別與理解
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支