2015年7月19日 星期日

正規的使用Handler更新畫面並且避免Handler Leaking發生

【可以先參考官方教學與範例。

真正讓我想出不用Handler、而用BroadCast的方式更新畫面的原因...在於Handler很難用!



產生Handler的程式碼如果不是直接在Activity類別內,這個Handler最後不被執行的可能性...八成!

最發生的現象就是...在一個獨立在Activity外寫成的Thread/Runnable類別內,有一段生成/宣告Handler的程式碼,不管這段程式碼是宣告一個匿名物件、或確實寫一個class,也不管它寫在run()內或run()外,.......經驗來判斷是:「這個Handler一律都不會被執行。」。

Android開發者稱這個現象叫做「Handler Leaking」。

在Log訊息中可以看到系統發出關於這個現象的警告,意思大概是說「這個Handler不是在Activity內產生的......」

這個「直接在Activity類別內」...意思是說連Fragment和View本身也涵蓋在其中!

其他可能會發生的現象還有...在Activity中寫了個匿名物件,內有產生Handler的程式碼,但這段程式碼卻不是在Activity內被執行的!

(我個人模糊的形容方式是:要滿足以下兩個條件才「絕對」不會發生HandlerLeaking:

1.類別在Activity中設置為內類別/巢狀類別。2.在Activity中宣告產生實體物件,包含匿名物件。

門檻其實挺高。)

雖然官方的教學範本裡面有說到要在Handler的建構子中傳入Looper.getMainLooper(),但這個方法也不管用!(沒有成功過!)



所以要用自己的變化與創意補足這塊了!

網路上看到過很多人使用Activity內增加Inner Class擴充Handler的方式來處理這個狀況,但我不採用。

因為這變成在Activity外使用Handler時,還要取得Activity當作參數傳入這個自設的Handler類別的建構子中。

現階段沒有辦法直接做到「隨意的產生Handler,然後又隨意決定Handler的功能,」只能做到最接近、最不花費力氣的方式...





這兩個介面/函數和Handler仍然需要在Activity中實作,但全部只有21行程式碼,而且只要做一次。


然後用上圖的方式,就可以在任何可以取道Context或Activity的地方產生帶有特定效果的Handler。




如果只是單純的要傳一個數值參數,用emptyMessage(int what)即可,為何還要有個Object參數?

仔細想想,Message類別中帶有一個Object參數讓使用者可以隨意傳入物件,真正的意義恐怕就在這裡。