1. 程式人生 > >為何Android開發中不推薦使用全域性變數傳參

為何Android開發中不推薦使用全域性變數傳參

Android開發中一般都是使用Intent給Activity傳參。有時需要傳複雜物件時,我們會傾向於用全域性變數(靜態變數或Application屬性)。但其實這樣做是有隱患的,跟Activity的生命週期有關,正好最近遇到這個問題,在這裡寫一下。

大概情況是這樣的:ActivityA中點選按鈕啟動ActivityB,同時要傳一個大資料物件,懶得對這個物件進行序列化,於是就直接搞了個全域性變數ActivityB.param寫了進去,在ActivityB.onCreate裡讀取並顯示資訊,編譯執行一切正常。這樣過了大半個月似乎也沒發現什麼問題。直到有一天發給客戶使用後,在友盟後臺看到了空指標錯誤,仔細分析堆疊程式碼,錯誤就在ActivityB.onCreate裡讀取全域性變數時發生,也就是全域性變數返回了空!

全域性變數為空一般就是由於記憶體不足程序被KILL過重新建立了。按常理分析,ActivityA在給ActivityB.param賦值後會立即啟動ActivityB,這過程很短,程序不可能這麼快被KILL,因此理論上ActivityB.onCreate中應該能讀取到ActivityB.param的。

實際上,在ActivityA給ActivityB.param賦值啟動ActivityB後,ActivityB.onCreate確實是能讀取到ActivityB.param的;但是,ActivityB並不能保證永遠在前臺,一旦ActivityB所在任務被切到後臺(如有電話打進來了),系統就可以在記憶體不足時將ActivityB所在的程序KILL掉;而當ActivityB所在任務被切回前臺(如電話打完了),這時系統會自動重新恢復ActivityB,這時全域性變數自然就沒了。

有人說我不用靜態變數,用Application的屬性來存全域性引數,是不是就可以避免這個問題了呢?其實也是不行的,因為程序被KILL再恢復後,Application物件也是銷燬重建了的;安卓系統並不保證會在KILL程序前給程式發通知,因此我們也無法在Application裡儲存恢復全域性變數。

另外,全域性變數也不能記錄安卓的介面Context相關的類(如Activity、View),因為安卓系統自動管理這些類,記錄它們會導致引用計數增加無法釋放的記憶體洩露問題;如果一定要記錄,則應該使用弱引用WeakReference。

總之安卓開發中是不推薦用全域性變數傳參的。最好的辦法還是按照安卓的開發規範,完全使用Intent進行傳參,因為系統在KILL程序前會自動儲存Activity堆疊,同時儲存相關的Intent引數,並自動進行恢復。如果非要用全域性變數,則至少必須在讀取全域性變數處理時判斷是否為空,避免程式出錯崩潰;同時最好在onPause時自行儲存資料以便被KILL後恢復。

但是我覺得全域性變數也不是一無是處完全不能用,主要是要理解並避開安卓程序生命週期中全域性變數的變化。例如用全域性變數來記錄自己寫的全域性處理類(如工廠類、類註冊器等),只要注意在被程序KILL後做好恢復工作,是完全可以的。