【Android 异步操作】手写 Handler ( 消息队列 MessageQueue | 消息保存到链表 | 从链表中获取消息 )
文章目錄
- 一、MessageQueue 消息隊列存儲消息
- 二、MessageQueue 消息隊列取出消息
- 三、消息隊列完整代碼
一、MessageQueue 消息隊列存儲消息
Message 鏈表 : 消息隊列 MessageQueue , 內部維護了一個 Message 鏈表 , 存儲的時候只存儲第一個 Message 即可 ;
鏈表插入元素 : 當 Handler 在其它線程調用 sendMessage 方法 , 將 消息 Message 放入 Looper 中的 MessageQueue 時 , 針對該鏈表的操作就是 , 循環獲取鏈表的下一個元素 , 最終 獲取到最后一個元素 , 最后一個元素的 next 為空 ; 將 最后一個元素的 next 設置為本次要插入的 Message , 即可完成消息存儲到消息隊列的操作 ;
鏈表元素同步 : 鏈表為空時 , 取出鏈表的操作會阻塞 , 調用的是 wait 方法 , 此時有消息加入鏈表后 , 需要 調用 notify 喚醒阻塞 ;
消息入隊的部分代碼 :
/*** 該隊列是一個鏈表 , 因此這里只給出第一個 Message 即可*/Message mMessage;/*** 將 Message 消息加入到 Message 鏈表中* @param msg*/public void enqueueMessage( Message msg ){// 因為 該消息隊列 可能會有多個線程 通過 Handler 向消息隊列中添加消息// 因此 需要使用同步代碼塊包裹以下邏輯synchronized (this){if( mMessage == null ){mMessage = msg;}else{/*如果鏈表不為空這里需要循環查找消息隊列的最后一個消息將本次傳入的 Message msg 參數加入到鏈表尾部*/Message pointer = mMessage;Message previous = pointer;for(;;){// 記錄上一條消息, 每次遍歷都將本次遍歷的記錄下來previous = pointer;// 將 pointer 指向下一條消息pointer = pointer.next;// 此時如果某個 Message 的 下一個元素為空// 說明該 Message 是消息隊列最后一個元素if(pointer == null){break;}}// 將本次參數傳入的 Message 放到鏈表最后previous.next = msg;}notify();}}二、MessageQueue 消息隊列取出消息
Looper 調用 loop 方法后 , 會一直循環 , 不斷地從 消息隊列 MessageQueue 中取出 Message 消息 , 然后 將 Message 消息發送給對應的 Handler 執行對應的操作 ;
從 消息隊列 MessageQueue 中取出消息 , 也是 取出鏈表表頭 的操作 , 取出該鏈表的表頭 , 然后 將表頭設置成鏈表的第二個元素 ;
消息同步 : 如果當前鏈表為空 , 此時會 調用 wait 方法阻塞 , 直到消息入隊時 , 鏈表中有了元素 , 會調用 notify 解除該阻塞 ;
/*** 從消息隊列中獲取消息* @return*/public Message next(){synchronized (this){// 本次要獲取的消息, 最后要返回到 Looper 中 loop 方法中Message result;for (;;){// 嘗試和獲取 消息隊列 鏈表中的第一個元素result = mMessage;if(result == null){// 如果當前的 Message 隊列為空 , 阻塞等待 , 直到新的消息到來try {wait();} catch (InterruptedException e) {e.printStackTrace();}}else{// 如果不為空 , 說明已經獲取到最終的消息 , 退出循環即可break;}}// 處理鏈表邏輯 , 將表頭指向下一個 MessagemMessage = mMessage.next;return result;}}三、消息隊列完整代碼
package kim.hsl.handler;public class MessageQueue {/*** 該隊列是一個鏈表 , 因此這里只給出第一個 Message 即可*/Message mMessage;/*** 將 Message 消息加入到 Message 鏈表中* @param msg*/public void enqueueMessage( Message msg ){// 因為 該消息隊列 可能會有多個線程 通過 Handler 向消息隊列中添加消息// 因此 需要使用同步代碼塊包裹以下邏輯synchronized (this){if( mMessage == null ){mMessage = msg;}else{/*如果鏈表不為空這里需要循環查找消息隊列的最后一個消息將本次傳入的 Message msg 參數加入到鏈表尾部*/Message pointer = mMessage;Message previous = pointer;for(;;){// 記錄上一條消息, 每次遍歷都將本次遍歷的記錄下來previous = pointer;// 將 pointer 指向下一條消息pointer = pointer.next;// 此時如果某個 Message 的 下一個元素為空// 說明該 Message 是消息隊列最后一個元素if(pointer == null){break;}}// 將本次參數傳入的 Message 放到鏈表最后previous.next = msg;}notify();}}/*** 從消息隊列中獲取消息* @return*/public Message next(){synchronized (this){// 本次要獲取的消息, 最后要返回到 Looper 中 loop 方法中Message result;for (;;){// 嘗試和獲取 消息隊列 鏈表中的第一個元素result = mMessage;if(result == null){// 如果當前的 Message 隊列為空 , 阻塞等待 , 直到新的消息到來try {wait();} catch (InterruptedException e) {e.printStackTrace();}}else{// 如果不為空 , 說明已經獲取到最終的消息 , 退出循環即可break;}}// 處理鏈表邏輯 , 將表頭指向下一個 MessagemMessage = mMessage.next;return result;}} }
總結
以上是生活随笔為你收集整理的【Android 异步操作】手写 Handler ( 消息队列 MessageQueue | 消息保存到链表 | 从链表中获取消息 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Android 异步操作】手写 Han
- 下一篇: 【Android 异步操作】手写 Han