Android解惑之Handler為什麼需要是static的

Munt發表於2020-12-02

我們先來看一張Android Studio中的warning截圖

Android解惑之Handler為什麼需要是static的

handler記憶體洩漏.png

Android解惑之Handler為什麼需要是static的

上面這段程式碼會引起記憶體洩漏(Memory Leak)。

  • 為什麼會引起記憶體洩漏?

    我們都知道,非static的內部類會持有外部類的引用,舉個類子來說,我們經常在一些內部類中顯示跳轉activity的時候,給Intent賦值的時候,第一個引數會寫 外部類名.this ,這就是持有外部類的引用的很好表現。 同樣,其他地方需要用到這個內部類的時候,也不能是直接new出來,因為為非static的,必須先通過new出外部類才能。

那麼,現在的情況就是,這個非static的handler內部類,無論是否是匿名的,便會持有外部的activity的引用。

若此時你的handler的訊息佇列中有未處理的Message,在Activity finish之後,Message仍然存在,那麼Handler也仍然存在。由於Handler中有Context的引用,那麼Context也就存在也就存在。而該Context就是我們的Activity,也就是Activity依然純在,那麼我們便是發生了記憶體洩露。

  • 那麼為什麼要寫成靜態內部類呢?或者寫成其他單獨的類呢?

    隱性匿名類Handler變成static的內部類,由於static的內部類,使用的使用不需要外部類的例項,所以static的內部類和外部類是沒有聯絡的,從而不持有外部類的引用,通過這種方法,我們可以避免該種情況的發生。

    將隱性匿名類寫成一個單獨的類(top-level-class),這樣Handler和Context之間就沒有聯絡了。

  • 如何寫?

    大家都知道,寫成靜態類後,由於其類似於單獨成為了一個類,便不能直接呼叫我們Activity中的一些控制元件了,難不成要把所有的控制元件都寫成static的麼,當然不是

我們通過使Handler持有Activity的一個弱引用來解決這個問題,直接持有Activity的話,我們便與之前的匿名內部類直接持有外部類的引用沒區別了,而持有了弱引用,在Activity有用的情況下,其會被AMS持有強引用,GC不會回收,而當其finish了,便沒有強引用物件持有了,此時GC時便會回收該Activity,我們的Handler由於是持有的弱引用,也不會導致其回收不成功。

來看一個簡單的demo,我們寫一個靜態handler,實現5秒後修改我們佈局中的textview的text。

Android解惑之Handler為什麼需要是static的

Android解惑之Handler為什麼需要是static的

可以看到,我們的Activity中的TextView成功被修改了。

Android解惑之Handler為什麼需要是static的

 

 

相關文章