版權聲明:緩存
本帳號發佈文章均來自公衆號,承香墨影(cxmyDev),版權歸承香墨影全部。安全
未經容許,不得轉載。網絡
在 Android 系統中,當運行的 App 被移動到後臺的以後,Android 爲了保證下次啓動的速度,會將它移入 Cached 的狀態,這個時候實際上,該 App 的進程依然存在,可是對應的組件是否存在,就不必定了。而既然該 App 的進程還存活着,下次啓動的速度就會很快,這就是常說的熱啓動。ide
可是這些被退出到後臺的 App ,也並非徹底安全不會被清理掉的,他們可能只是沒有持有任何的組件,而且是不佔用 CPU 資源的,可是它依然會佔據內存空間。而當系統認爲內存不足的時候,就會按照優先級清理掉一些優先級不那麼高的進程,來回收一些內存空間,供新啓動的程序使用,這就是 LowMemoryKiller 的策略。性能
那麼,爲了讓咱們的 App 在後臺儘量活的久一點,無非就是將內存下降,從而使得優先級提升,而實現不被系統回收的功能(這是一個常規的優化方案,而非保活方案)。那麼,若是咱們能明確當前 App 處於什麼狀態,就能在此時機,釋放一些不須要持有的內存資源,來達到咱們的目的。優化
這個時候,就須要用到 onTrimMemory()
這個回調方法了。spa
前面提到,咱們能夠經過實現 onTrimMemory()
方法,來完成對當前 App 在內存中的優先級的簡單管理。3d
而 onTrimMemory()
回調方法,是 Android Level 14(Android 4.0) 以後提供的一個 API,它主要的做用是提醒開發者,在系統內存不足的時候,應該經過釋放部分不重要的內存資源,從而避免被 Android 系統服務殺掉。code
能夠看到,onTrimMemory()
本質上是一種告知 App 處於系統內存回收的不一樣階段的時機,應該在這些時機,合理對自身持有的內存進行釋放,以免被系統直接殺掉,從而讓保證下次用戶啓動 App 時候的速度。cdn
onTrimMemory()
的完整方法簽名以下:
public void onTrimMemory(int level)複製代碼
能夠看到,它實際上,會有一個 level 參數來標記當前的 App 在內存中的級別,也就意味着 onTrimMemory()
方法,可能會被屢次調用到。
既然 onTrimMemory()
方法會傳遞一個 level 參數,那麼就先來看看,各類 level 參數所表明的含義。
其實從 level 值的取名來看,大體能夠分爲三類:
這三類中,一般咱們只須要關心 App 被置於 Cached 狀態下的狀況,由於系統是不會殺掉一個正在前臺運行的 App 的(但可能會觸發 OOM),可是若是該 App 有一些後臺服務正在運行,這個服務也是有被殺的風險的。
而在 Cached 狀態下的時候,當收到 TRIM_MEMORY_Xxx 的回調,就須要注意了,這些只是標記了當前 App 處於 LRU List 的位置,也就是說,若是回收了靠前的 App 進程以後,依然達不到內存使用的要求,可能會進一步去殺進程,也就是說,極端狀況下,可能從 TRIM_MEMORY_BACKGROUND 到 TRIM_MEMORY_COMPLETE 是瞬間完成的事情,因此咱們須要慎重處理它們,儘可能對這三個狀態都進行判斷,而後作統一的回收內存資源的處理。
既然說到了 onTrimMemory()
回掉,看樣子它是和 App 相關的,因此最少在 Application 中,應該是能夠對其進行重寫來監聽回調的。可是除了 Application,其餘的一些組件中,也是能夠監聽它的。
這些能夠監聽 onTrimMemory 的組件有:
除了前面提到的系統默承認以監聽 onTrimMemory()
的組件以外,咱們還能夠自定義 onTrimMemory 的監聽。
自定義起來也很是的簡單,只須要實現 ComponentCallbacks2 接口,而後調用 Application.registerComponentCallbacks()
方法註冊便可。
除了 registerComponentCallbacks()
方法進行註冊監聽以外,若是不使用了的話,還可使用 unregisterComponentCallbacks()
進行解注。
那麼這裏是如何實現的呢?讓咱們來看看 Application 的對應源碼。
能夠看到,它其實是經過一個 mComponentCallbacks 的列表進行維護的。
而在 onTrimMemory()
的時候,又從 mComponentCallbacks 中獲取到全部的 callbacks 對象,進行消息的分發。
經過這種方式實現了對 onTrimMemory()
的自定義監聽。
而 onTrimMemory()
方法同時被標記爲 @CallSuper,也就嚴格要求了重寫它的子類,必須調用父類中的 onTrimMemory()
方法,從而保證了消息的分發不會缺失。
onTrimMemory()
既然是 Android 4.0 才新增長的 Api,那麼對於低版本的設備而言,能夠監聽 onLowMemory()
方法,它大概能夠等同於 level 級別爲 TRIM_MEMORY_COMPLETE 的回調。
固然,ComponentCallbacks2 接口繼承的 ComponentCallback 接口,也是須要實現 onLowMemory()
方法的。
Android 系統會在自身內存不足的狀況下,清理掉一些不重要的進程來釋放內存資源,以供優先級更高的進程使用。而這個順序,主要是按照 LRU List 中的優先級來清理的,可是它也同時會考慮清理掉哪些佔用內存較高的進程來讓系統更快的釋放跟多的內存。
因此,儘量的讓 App 在系統內,佔用足夠小的內存資源,就能夠下降被殺的機率,從而下次啓動的時候走熱啓動的方式,提高用戶的體驗。
換一個角度來講,讓 App 佔用較小的內存,也能夠優化系統的速度,畢竟系統清理進程釋放內存的過程,也是須要佔用 CPU 資源的。在大環境下,也是有意義的。
因此,在 onTrimMemory()
的時機,對當前 App 的內存進行釋放優化,就尤其重要了。
在 onTrimMemory()
回調中,應該在一些狀態下清理掉不重要的內存資源。在不考慮內存泄露的狀況下,有一些資源是咱們主動緩存起來,以便咱們在使用的過程當中能夠快速獲取,而這部分資源就是咱們清理的重點。
對於這些緩存,只要是讀進內存內的都算,例如最多見的圖片緩存、文件緩存等。拿圖片緩存來講,市場上,常規的圖片加載庫,通常而言都是三級緩存,因此在內存吃緊的時候,咱們就應該優先清理掉這部分圖片緩存,畢竟圖片是吃內存大戶,並且再次回來的時候,雖然內存中的資源被回收掉了,咱們依然能夠從磁盤或者網絡上恢復它。
除了資源緩存以外,還有一些頁面相關的資源,也是佔據內存的,能夠考慮清理掉 Activity Task 中,多餘的 Activity,只保留 Root Activity 。
其實核心思想,就是根據 onTrimMemory()
回調的一些信息,來釋放咱們持有的可被恢復,不那麼重要的內存資源,以提升系統性能,已經保證當前 App 的進程不那麼容易被系統回收。