對Application類的理解

首先,Application在一個Dalvik虛擬機裏面只會存在一個實例,所以你不要傻傻的去弄什麼單例模式,來靜態獲取Application了,你把Application構造函數設置成privete都不可能實現(我年輕的時候就這麼傻傻的試過,想着如果可以通過Singleton.getInstance()就能獲取到Application對象,多爽呀~)。

那麼爲什麼強調說是一個Dalvik虛擬機,而不是說一個App呢?

因爲一個App有可能有多個Dalvik虛擬機,也就是傳說中的多進程模式。在這種模式下,每一個Dalvik都會存在一個Application實例,他們之間沒有關係,在A進程Application裏面保存的數據不能在B進程的Application獲取,因爲他們根本不是一個對象,而且被隔離在了兩個進程裏面,所以這裏強調是一個Dalvik虛擬機,而不是一個App。

其次,Application的實質是一個Context,它繼承自ContextWrapper。

android.content.Context
       ↳  android.content.ContextWrapper
        ↳ android.app.Application  

ContextWrapper是什麼玩意?就是對Context的一個包裝而已。

Application有兩個子類,一個是MultiDexApplication,如果你遇到了"65535"問題,可以選擇繼承自他,完成多Dex打包配置的相關工作。

另外一個是在TDD(測試用例驅動)開發模式中使用Moke進行測試的時候用到的,可以來代替Application的Moke類MockApplication。

在應用啓動的時候,會首先調用Application.attach(),當然,這個方法是隱藏的,開發者能接觸到的第一個被調用的方法其實是Application.onCreate(),我們通常會在這個方法裏面完成各種初始化,比如圖片加載庫、Http請求庫的默認配置初始化操作等等。但是最好別在這個方法裏面進行太多耗時操作,因爲這會影響App的啓動速度,所以對於不必要的操作可以使用異步操作、懶加載、延時加載等策略來減少對UI線程的影響。

除此之外,由於在Context中可以通過getApplicationContext()獲取到Application對象,或者是通過Activity.getApplication()、Service.getApplication()獲取到Application,所以可以在Application保存全局的數據,供所有的Activity或者是Service使用。

PS:使用上面的三種方法獲取到的都是同一個Application對象,getApplicationContext()是在Context的實現類ContextImpl中具體實現的,而getApplication()則是在Activity和Service中單獨實現的,所以他們的作用域不同,但是獲取到的都是同一個Application對象,因爲一個Dalvik虛擬機只有一個Application對象。

但是這裏存在着一個坑,那就是在低內存情況下,Application有可能被銷燬,從而導致保存在Application裏面的數據信息丟失,最後程序錯亂,甚至是Crash。

所以當你想在Application保存數據的時候,請做好爲空判斷,或者是選擇其他方式保存你的數據信息。

另外,在Application中存在着幾個有用的方法,比如onLowMemory()和onTrimMemory(),在這兩個方法裏面,我們可以實現自己的內存回收邏輯,比如關閉數據庫連接、移除圖片內存緩存等操作來降低內存消耗,從而降低被系統回收的風險。

最後,就是要注意Application的生命週期,他和Dalvik虛擬機生命週期一樣長,所以在進行單例或者是靜態變量的初始化操作時,一定要用Application作爲Context進行初始化,否則會造成內存泄露的發生。使用Dialog的時候一般使用Activity作爲Context,但是也可以使用Application作爲上下文,前提是你必須設置Window類型爲TYPE_SYSTEM_DIALOG,並且申請相關權限。這個時候彈出的Dialog是屬於整個Application的,彈出這個Dialog的Activity銷燬時也不會回收Dialog,只有在Application銷燬時,這個Dialog纔會自動消失。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章