背景
最近接手新項目,遇到了一個跟 Handler 有關的 Bug,在解決過程中耗費了挺多時間的,最後通過另外的思路解決了。
在此通過本篇文章分享給大家,也爲大家後面遇到 Handler 相關問題時能快速定位解決。
問題描述
問題點在於 Handler 發送的消息沒有在 handleMessage 收到。
當然發送消息的地方和接受消息的地方不是同一個文件。
可以認爲 Handler 通過 HashMap 統一管理起來。
思路 1
會不會發送的 Handler 跟接收的 Handler 不是同一個?
畢竟是通過 HashMap 管理,有可能被替換了?
驗證方法:打印一下 Handler 的引用就可以確認,結果是同一個 Handler。
思路 2
會不會發送的消息被 remove 掉了?
驗證方法:通過新引入一個唯一的 msg.what 來確認,結果也沒有收到。
思路 3
/**
* Sends a Message containing only the what value.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
通過源碼的註釋,發現消息如果已經在隊列,是不會再塞進去的,但是如果隊列已經存在,也不應該收不到啊。
最後打印返回值也是正確的。
雖然這個思路沒有解決問題,但是由於這個,打開了另一個思路,那就是會不會隊列阻塞了,消息卡住了?
最終驗證方法
因此最終通過引入 IdleHandler 來驗證到底消息隊列是不是出問題了,沒有空閒消息回調。
關於 IdleHandler,我簡單說明下,一般是在 Handler 空閒時會回調,如果你監聽後沒有移除,會一直回調。
用法之一是延遲初始化,提高界面渲染速度。
更多資料見:
最終確認了,在這個發送消息的線程(子線程)裏面使用 IdleHandler 沒有回調,而原先的 Handler 是在主線程構建的。
因此根源是由於修改了 Handler 的線程,而所在的子線程消息不斷的產生消息造成隊列可能一直被佔用,因此新發的消息收不到。
隨着Android開發行業逐漸飽和,對Android開發者的面試要求也越來越高,是否掌握底層源碼,便是考驗一名Android開發者的重要一環。面試被問到源碼問題答不出來,會掉身價、砍薪資尚且不談,甚至連面試都過不了!
網上各類源碼解析的文章博客五花八門、良莠不齊。雜亂、要麼內容質量太淺,零散、碎片化,總看着看着就銜接不上了。
這裏最後分享耗時一年多整理的一系列Android學習資源:Android源碼解析、Android第三方庫源碼筆記、Android進階架構師七大專題學習、歷年BAT面試題解析包、Android大佬學習筆記等等,這些內容均免費分享給大家,需要完整版的朋友,點這裏可以看到全部內容