Application和Activity、Service一樣是android框架的一個(gè)系統(tǒng)組件沾瓦,當(dāng)android程序啟動(dòng)時(shí)系統(tǒng)會(huì)創(chuàng)建一個(gè)application對(duì)象,用來存儲(chǔ)系統(tǒng)的一些信息。通常我們是不需要指定一個(gè)Application的贯莺,這時(shí)系統(tǒng)會(huì)自動(dòng)幫我們創(chuàng)建风喇,如果需要?jiǎng)?chuàng)建自己的Application,也很簡(jiǎn)單創(chuàng)建一個(gè)類繼承Application并在manifest的application標(biāo)簽中進(jìn)行注冊(cè)(只需要給Application標(biāo)簽增加個(gè)name屬性把自己的Application的名字定入即可)缕探。
因?yàn)锳pplication是全局的單例的魂莫,所以在不同的Activity、Service中獲得的對(duì)象都是同一個(gè)對(duì)象爹耗。通過Application來進(jìn)行一些耙考,數(shù)據(jù)傳遞,數(shù)據(jù)共享等鲸沮,數(shù)據(jù)緩存等操作琳骡。
Data passing between components using Application
假如有一個(gè)Activity A,跳轉(zhuǎn)到Activity B,并需要推薦一些數(shù)據(jù)讼溺,通常的作法是Intent.putExtra()讓Intent攜帶楣号,或者有一個(gè)Bundle把信息假如Bundle讓Intent推薦Bundle對(duì)象,實(shí)現(xiàn)傳遞怒坯。但這樣做有一個(gè)問題在于炫狱,Intent和Bundle所能攜帶的數(shù)據(jù)類型都是一些基本的數(shù)據(jù)類型,如果想要實(shí)現(xiàn)復(fù)雜的數(shù)據(jù)傳遞就比較麻煩了剔猿,通常需要實(shí)現(xiàn)Serializable或者Parcellable接口视译。這其實(shí)是Android的一種IPC數(shù)據(jù)傳遞的方法。如果我們的兩個(gè)Activity在同一個(gè)進(jìn)程中為什么還要這么麻煩呢归敬,只要把需要傳遞的對(duì)象的引用傳遞過去就可以了酷含。
基本思路是這樣的,在Application中創(chuàng)建一個(gè)HashMap<String,Object>汪茧,以字符串為索引椅亚,Object為value這樣我們的HashMap就可以存儲(chǔ)任何類型的對(duì)象了。在Activity A中把需要傳遞的對(duì)象放入這個(gè)HashMap舱污,然后通過Intent或者其它途徑再把這個(gè)索引的字符串傳遞給Activity B呀舔,Activity B就可以根據(jù)這個(gè)字符串在HashMap中提取出這個(gè)對(duì)象了。只要再向下轉(zhuǎn)個(gè)型扩灯,就實(shí)現(xiàn)了對(duì)象的傳遞媚赖。
Data caching in Application
我一般習(xí)慣在Application中建立兩個(gè)HashMap一個(gè)用于數(shù)據(jù)的傳遞,一個(gè)用于緩存一些數(shù)據(jù)珠插。
比如有一個(gè)Activity需要從網(wǎng)站獲取一些數(shù)據(jù)惧磺,獲取完之后我們就可以把這個(gè)數(shù)據(jù)cache到Application當(dāng)中,當(dāng)頁面設(shè)置到其它Activity再回來的時(shí)候捻撑,就可以直接使用緩存好的數(shù)據(jù)了豺妓。但如果需要cache一些大量的數(shù)據(jù)惜互,最好是cache一些 (軟引用)SoftReference ,并把這些數(shù)據(jù)cache到本地rom上或者sd卡上琳拭。如果在application中的緩存不存在训堆,從本地緩存查找,如果本地緩存的數(shù)據(jù)也不存在再?gòu)木W(wǎng) 絡(luò)上獲取白嘁。
PitFalls
使用Application如果保存了一些不該保存的對(duì)象很容易導(dǎo)致內(nèi)存泄漏坑鱼。如果在Application中的onCreate中執(zhí)行比較耗時(shí)的操作,將直接影響程序的啟動(dòng)時(shí)間絮缅。這些清理工作不能依靠onTerminate完成鲁沥,因?yàn)閍ndroid會(huì)盡量讓你的程序一直運(yùn)行,所以很可能onTerminate不會(huì)被調(diào)用耕魄。
MemoryLeak
在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的引用。
通常情況下则奥,當(dāng)用戶轉(zhuǎn)動(dòng)手機(jī)的時(shí)候考润,android會(huì)重新調(diào)用OnCreate()方法生成一個(gè)新的Activity,原來的 Activity應(yīng)該被GC所回收读处。但如果有個(gè)對(duì)象比如一個(gè)View的作用域超過了這個(gè)Activity(比如有一個(gè)static對(duì)象或者我們把這個(gè) View的引用放到了Application當(dāng)中)糊治,這時(shí)候原來的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ù)還沒有執(zhí)行完畢并持有Activity的引用而泄漏搀菩,但這種泄漏一般來泄漏一段時(shí)間呕臂,只有Runnalbe的線程執(zhí)行完閉,這個(gè) Activity又可以被正撤景希回收了歧蒋。
4,內(nèi)存類的對(duì)象作用域超出Activity的范圍:比如定義了一個(gè)內(nèi)存類來存儲(chǔ)數(shù)據(jù),又把這個(gè)內(nèi)存類的對(duì)象傳給了其它Activity 或者Service等谜洽。因?yàn)閮?nèi)部類的對(duì)象會(huì)持有當(dāng)前類的引用萝映,所以也就持有了Context的引用。解決方法是如果不需要當(dāng)前的引用把內(nèi)部類寫成 static或者阐虚,把內(nèi)部類抽取出來變成一個(gè)單獨(dú)的類序臂,或者把避免內(nèi)部對(duì)象作用域超出Activity的作用域。
out Of Memery Error 在android中每一個(gè)程序所分到的內(nèi)存大小是有限的实束,如果超過了這個(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)构订。
Android使用Application
首先需要重寫Application,主要重寫里面的onCreate方法避矢,就是創(chuàng)建的時(shí)候悼瘾,初始化變量的值。然后在整個(gè)應(yīng)用中的各個(gè)文件中就可以對(duì)該變量進(jìn)行操作了谷异。啟動(dòng)Application時(shí)分尸,系統(tǒng)會(huì)創(chuàng)建一個(gè)PID,即進(jìn)程ID歹嘹,所有的Activity就會(huì)在此進(jìn)程上運(yùn)行箩绍。那么我們?cè)贏pplication創(chuàng)建的時(shí)候初始化全局變量,同一個(gè)應(yīng)用的 所有Activity都可以取到這些全局變量的值尺上,換句話說材蛛,我們?cè)谀骋粋€(gè)Activity中改變了這些全局變量的值,那么在同一個(gè)應(yīng)用的其他Activity中值就會(huì)改變怎抛。
步驟:
第一步卑吭,寫一個(gè)全局的單例模式的MyApplication繼承自Application覆蓋onCreate,在這個(gè)方法里面實(shí)例化Application。
第二步马绝,配置全局的Context
<application
android:name="com.example.utils.myapplication"
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
</application>
第三步豆赏,使用的時(shí)候根據(jù)類的名稱訪問Context
android.app.Application類包含了4個(gè)公開的方法
void onConfigurationChanged(Configuration newConfig)
void onCreate() //這里才是真正的入口點(diǎn)
void onLowMemory()
void onTerminate()
說明:
onCreate();這個(gè)函數(shù)是當(dāng)我們的應(yīng)用開始之時(shí)就被調(diào)用了富稻,比應(yīng)用中的其他對(duì)象創(chuàng)建的早掷邦,這個(gè)實(shí)現(xiàn)盡可能快一點(diǎn),因?yàn)檫@個(gè)時(shí)間直接影響到我們第一個(gè)Activity/service/receiver椭赋。如果你要重寫這個(gè)方法必須調(diào)用super.onCreate().
onTerminate()這個(gè)函數(shù)是模擬一個(gè)過程環(huán)境抚岗,在真機(jī)中永遠(yuǎn)不會(huì)調(diào)用。
public class MyApplication extends Application
在Activity中要引用定義的變量或方法時(shí)哪怔,首先定義一個(gè)對(duì)象
private MyApplication app;
app = (MyApplication)getApplication();//獲取MyApplication對(duì)象
然后就可以利用其方法了宣蔚。
注:只需要調(diào)用Context的getApplicationContext或者Activity的getApplication方法來獲得一個(gè)Application對(duì)象向抢,然后再得到相應(yīng)的成員變量接口。它是代表我們的應(yīng)用程序的類胚委,使用它可以獲得當(dāng)前應(yīng)用的主題和資源文件中的內(nèi)容等挟鸠。