Application和Activity,Service一樣是android框架的一個(gè)系統(tǒng)組件,當(dāng)android程序啟動(dòng)時(shí)系統(tǒng)會(huì)創(chuàng)建一個(gè) application對(duì)象,用來(lái)存儲(chǔ)系統(tǒng)的一些信息。通常我們是不需要指定一個(gè)Application的,這時(shí)系統(tǒng)會(huì)自動(dòng)幫我們創(chuàng)建,如果需要?jiǎng)?chuàng)建自己 的Application,也很簡(jiǎn)單創(chuàng)建一個(gè)類(lèi)繼承 Application并在manifest的application標(biāo)簽中進(jìn)行注冊(cè)(只需要給Application標(biāo)簽增加個(gè)name屬性把自己的 Application的名字定入即可)。
android系統(tǒng)會(huì)為每個(gè)程序運(yùn)行時(shí)創(chuàng)建一個(gè)Application類(lèi)的對(duì)象且僅創(chuàng)建一個(gè),所以Application可以說(shuō)是單例 (singleton)模式的一個(gè)類(lèi).且application對(duì)象的生命周期是整個(gè)程序中最長(zhǎng)的,它的生命周期就等于這個(gè)程序的生命周期。因?yàn)樗侨?的單例的,所以在不同的Activity,Service中獲得的對(duì)象都是同一個(gè)對(duì)象。所以通過(guò)Application來(lái)進(jìn)行一些,數(shù)據(jù)傳遞,數(shù)據(jù)共享 等,數(shù)據(jù)緩存等操作。
假如有一個(gè)Activity A, 跳轉(zhuǎn)到 Activity B ,并需要推薦一些數(shù)據(jù),通常的作法是Intent.putExtra() 讓Intent攜帶,或者有一個(gè)Bundle把信息加入Bundle讓Intent推薦Bundle對(duì)象,實(shí)現(xiàn)傳遞。但這樣作有一個(gè)問(wèn)題在 于,Intent和Bundle所能攜帶的數(shù)據(jù)類(lèi)型都是一些基本的數(shù)據(jù)類(lèi)型,如果想實(shí)現(xiàn)復(fù)雜的數(shù)據(jù)傳遞就比較麻煩了,通常需要實(shí)現(xiàn) Serializable或者Parcellable接口。這其實(shí)是Android的一種IPC數(shù)據(jù)傳遞的方法。如果我們的兩個(gè)Activity在同一個(gè) 進(jìn)程當(dāng)中為什么還要這么麻煩呢,只要把需要傳遞的對(duì)象的引用傳遞過(guò)去就可以了。
基本思路是這樣的。在Application中創(chuàng)建一個(gè)HashMap<String,Object> ,以字符串為索引,Object為value這樣我們的HashMap就可以存儲(chǔ)任何類(lèi)型的對(duì)象了。在Activity A中把需要傳遞的對(duì)象放入這個(gè)HashMap,然后通過(guò)Intent或者其它途經(jīng)再把這人索引的字符串傳遞給Activity B ,Activity B 就可以根據(jù)這個(gè)字符串在HashMap中取出這個(gè)對(duì)象了。只要再向下轉(zhuǎn)個(gè)型 ,就實(shí)現(xiàn)了對(duì)象的傳遞。
我一般會(huì)習(xí)慣在application中建立兩個(gè)HashMap<String,Object>一個(gè)用于數(shù)據(jù)的傳遞,一個(gè)用于緩 存一些數(shù)據(jù)。比如有一個(gè)Activity需要從網(wǎng)站獲取一些數(shù)據(jù),獲取完之后我們就可以把這個(gè)數(shù)據(jù)cache到Application 當(dāng)中,當(dāng)頁(yè)面設(shè)置到其它Activity再回來(lái)的時(shí)候,就可以直接使用緩存好的數(shù)據(jù)了。但如果需要cache一些大量的數(shù)據(jù),最好是cache一些 (軟引用)SoftReference ,并把這些數(shù)據(jù)cache到本地rom上或者sd卡上。如果在application中的緩存不存在,從本地緩存查找,如果本地緩存的數(shù)據(jù)也不存在再?gòu)木W(wǎng) 絡(luò)上獲取。
使用Application如果保存了一些不該保存的對(duì)象很容易導(dǎo)致內(nèi)存泄漏。如果在Application的oncreate中執(zhí)行比較 耗時(shí)的操作,將直接影響的程序的啟動(dòng)時(shí)間。不些清理工作不能依靠onTerminate完成,因?yàn)閍ndroid會(huì)盡量讓你的程序一直運(yùn)行,所以很有可能 onTerminate不會(huì)被調(diào)用。
在Java中內(nèi)存泄漏是只,某個(gè)(某些)對(duì)象已經(jīng)不在被使用應(yīng)該被gc所回收,但有一個(gè)對(duì)象持有這個(gè)對(duì)象的引用而阻止這個(gè)對(duì)象被回收。比如我 們通常會(huì)這樣創(chuàng)建一個(gè)View TextView tv = new TextView(this);這里的this通常都是Activity。所以這個(gè)TextView就持有著這個(gè)Activity的引用。下面看張圖 (Google IO 2011 ppt中抄得)
通常情況下,當(dāng)用戶轉(zhuǎn)動(dòng)手機(jī)的時(shí)候,android會(huì)重新調(diào)用OnCreate()方法生成一個(gè)新的Activity,原來(lái)的 Activity應(yīng)該被GC所回收。但如果有個(gè)對(duì)象比如一個(gè)View的作用域超過(guò)了這個(gè)Activity(比如有一個(gè)static對(duì)象或者我們把這個(gè) View的引用放到了Application當(dāng)中),這時(shí)候原來(lái)的Activity將不能被GC所回收,Activity本身又持有很多對(duì)象的引用,所以 整個(gè)Activity的內(nèi)存被泄漏了。
經(jīng)常導(dǎo)致內(nèi)存泄漏的一些原因:
keeping a long-lived reference to a Context.持有一個(gè)context的對(duì)象,從而gc不能回收。
1,一個(gè)View,的作用域超出了所在的Activity的作用域,比如一個(gè)static的View或者 把一個(gè)View cache到了application當(dāng)中 etc
2,某些與View關(guān)聯(lián)的Drawable的作用域超出了Activity的作用域。
3,Runnable對(duì)象:比如在一個(gè)Activity中啟用了一個(gè)新線程去執(zhí)行一個(gè)任務(wù),在這期間這個(gè)Activity被系統(tǒng)回收了, 但Runnalbe的任務(wù)還沒(méi)有執(zhí)行完畢并持有Activity的引用而泄漏,但這種泄漏一般來(lái)泄漏一段時(shí)間,只有Runnalbe的線程執(zhí)行完閉,這個(gè) Activity又可以被正?;厥樟?。
4,內(nèi)存類(lèi)的對(duì)象作用域超出Activity的范圍:比如定義了一個(gè)內(nèi)存類(lèi)來(lái)存儲(chǔ)數(shù)據(jù),又把這個(gè)內(nèi)存類(lèi)的對(duì)象傳給了其它Activity 或者Service等。因?yàn)閮?nèi)部類(lèi)的對(duì)象會(huì)持有當(dāng)前類(lèi)的引用,所以也就持有了Context的引用。解決方法是如果不需要當(dāng)前的引用把內(nèi)部類(lèi)寫(xiě)成 static或者,把內(nèi)部類(lèi)抽取出來(lái)變成一個(gè)單獨(dú)的類(lèi),或者把避免內(nèi)部對(duì)象作用域超出Activity的作用域。
out Of Memery Error 在android中每一個(gè)程序所分到的內(nèi)存大小是有限的,如果超過(guò)了這個(gè)數(shù)就會(huì)報(bào)Out Of Memory Error。android給程序分配的內(nèi)存大小與手機(jī)硬件有關(guān),以下是一些手機(jī)的數(shù)據(jù):
G1:16M Droid:24 Nexus One:32M Xoom:48Ms
所以盡量把程序中的一些大的數(shù)據(jù)cache到本地文件。以免內(nèi)存使用量超標(biāo)。
1,通過(guò)Application在兩個(gè)Activity間傳遞數(shù)據(jù)
記得數(shù)據(jù)傳遞完成之后,把存放在application的HashMap中的數(shù)據(jù)remove掉,以免發(fā)生內(nèi)存的泄漏。
其實(shí)我們開(kāi)發(fā)的每個(gè)android應(yīng)用程序就是一個(gè)Appliction,定義這個(gè)類(lèi)往往是在AndroidManifes.xml中用到。例如:
< application android:icon = "@drawable/icon" |
android:label = "@string/app_name" |
android:name = ".MyApplication" > |
public class MyApplication extends Application
{ |
} |