Application是什么
Application和Activity哼蛆,Service一樣,是Android框架的一個系統(tǒng)組件骚勘,當(dāng)Android程序啟動是系統(tǒng)會創(chuàng)建一個Application對象猾编,用來存儲系統(tǒng)的一些信息桥爽。通常我們是不需要制定一個Application的纳击,這時系統(tǒng)會自動幫我們創(chuàng)建休建,如果需要創(chuàng)建自己的Application,創(chuàng)建一個類繼承Application并在manifests的application標(biāo)簽中進(jìn)行注冊(只需要給application標(biāo)簽增加個name屬性吧自己的Application的名字寫入)评疗。Android系統(tǒng)會為每個程序運行是創(chuàng)建一個Application的類的對象且僅創(chuàng)建一個,所以Application可以說是單例(singleton)模式的一個類茵烈,且application對象的生命周期是整個程序中最長的百匆,生命周期就是這個程序的生命周期。因為他是全局的單例的呜投,所以在不同的Activity加匈,Service中獲得的對象都是同一個對象。所以通過Application來進(jìn)行一些數(shù)據(jù)傳遞仑荐,數(shù)據(jù)共享雕拼,數(shù)據(jù)緩存等操作。
Application生命周期
registerComponentCallbacks()&unregisterComponentCallbacks():
注冊和注銷ComponentCallbacks2回調(diào)接口粘招,本質(zhì)上是復(fù)寫ComponentCallbacks2回調(diào)接口里的方法從未實現(xiàn)更多的操作啥寇。
registerComponentCallbacke(new ComponentCallbacks2()){
@Override public void onTriMemory(int level){}
@Override public void onLowMemory(){}
@Override public void onConfigurationChanged(Configuration newConfig){}
}
registerActivityLifecycleCallbacks()&unregisterActivityLifecycleCallbacks():
注冊注銷對應(yīng)用程序內(nèi)所有Activity的生命周期監(jiān)聽。當(dāng)應(yīng)用程序內(nèi)Activity生命周期發(fā)生變化時就會調(diào)用,實際上是調(diào)用registerActivityLifecycleCallbacks()里ActivityLifecycleCallbacks接口里的方法辑甜。
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks(){
@Override public void onActivity Created(Activity activity, Bundle saveInstanceState){}
@Override public void onActivityStarted(Activity activity){
Log.d(TAG,"onActivityStarted: "+ activity.getLocalClassName());? ? ? ? ? ? }
@Override public void onActivityResumed(Activity activity){
Log.d(TAG,"onActivityResumed: "+ activity.getLocalClassName());? ? ? ? ? ? }
@Override public void onActivityPaused(Activity activity){
Log.d(TAG,"onActivityPaused: "+ activity.getLocalClassName());? ? ? ? ? ? }
@Override public void onActivityStopped(Activity activity){
Log.d(TAG,"onActivityStopped: "+ activity.getLocalClassName());? ? ? ? ? ? }
@Override public void onActivitySaveInstanceState(Activity activity, Bundle outState){? ? ? ? ? ? }
@Override public void onActivityDestroyed(Activity activity){
Log.d(TAG,"onActivityDestroyed: "+ activity.getLocalClassName());? ? ? ? ? ? }
})
public void onCreate();在應(yīng)用程序創(chuàng)建的時候調(diào)用衰絮,可以實現(xiàn)這個方法來創(chuàng)建和實例化任何應(yīng)用程序狀態(tài)變量或共享資源。還可以在這個方法里面得到Application的單例磷醋。不要進(jìn)行耗時操作猫牡,否則會拖慢應(yīng)用程序的啟動速度。
public void onTerminate(); 當(dāng)終止應(yīng)用程序?qū)ο髸r調(diào)用邓线,不保證一定被調(diào)用淌友,當(dāng)程序時被內(nèi)核終止以便為其他應(yīng)用程序釋放資源,那么不會提醒骇陈,并且不調(diào)用應(yīng)用程序?qū)ο蟮膐nTerminate方法而直接終止進(jìn)程震庭。
public void onLowMemory(); 當(dāng)系統(tǒng)資源匱乏的時候,我們可以在這里可以釋放額外的內(nèi)存缩歪,這個方法一般只會在后臺進(jìn)程已經(jīng)結(jié)束归薛,但前臺應(yīng)用程序還是缺少內(nèi)存時調(diào)用》蓑可以重寫這個方法來清空緩存或者不必要的資源主籍。
public void onTrimMemory(int level);
OnTrimMemory()是 OnLowMemory() Android 4.0后的替代 API,OnLowMemory()= OnTrimMemory()中的TRIM_MEMORY_COMPLETE級別。當(dāng)運行時決定當(dāng)前應(yīng)用程序應(yīng)該減少其內(nèi)存開銷時(通常進(jìn)入后臺運行時調(diào)用)逛球,包含一個level參數(shù)千元,用于提供請求的上下文。
這里有傳入一個int類型的參數(shù)level颤绕,它告訴APP們內(nèi)存不足的嚴(yán)重性(越高越嚴(yán)重)幸海。假如這時候系統(tǒng)內(nèi)存不足,運行著前臺和后臺一共幾個APP奥务,這些不同的APP會收到系統(tǒng)不同的“勸告信息”:
TRIM_MEMORY_RUNNING_MODERATE:數(shù)值為5物独,系統(tǒng)內(nèi)存不足,前臺app釋放不用的內(nèi)存氯葬,內(nèi)存不夠殺掉其他應(yīng)用程序挡篓。
TRIM_MEMORY_RUNNING_LOW:數(shù)值10,系統(tǒng)內(nèi)存嚴(yán)重不足帚称,前臺app釋放不用的內(nèi)存官研,內(nèi)存不夠殺掉其他多個應(yīng)用程序。
TRIM_MEMORY_RUNNING_CRITICAL:數(shù)值15闯睹,系統(tǒng)內(nèi)存嚴(yán)重不足可能都不足以支撐該前臺app的(執(zhí)行onLowMemory()方法)
TRIM_MEMORY_UI_HIDDEN:數(shù)值20戏羽,系統(tǒng)把APP從前臺切換到后臺÷コ裕回收UI資源始花。
TRIM_MEMORY_BACKGROUND :數(shù)值40妄讯,內(nèi)存不足,殺掉后臺APP
TRIM_MEMORY_MODERATE :數(shù)值60衙荐,已進(jìn)入LRU緩存列表的中間位置捞挥,如果后面的APP進(jìn)程資源都被回收的話,下一個就是輪到它了
TRIM_MEMORY_COMPLETE :數(shù)值80已處于LRU緩存列表的后面位置忧吟,APP隨時都有被回收的風(fēng)險
public void onConfigurationChanged(Configuration newConfig); 與Activity不同砌函,配置改變時,應(yīng)用程序不會終止和重啟溜族。如果應(yīng)用程序使用的值依賴于特定的配置讹俊,則重寫這個方法來加載這些值,或者在應(yīng)用程序級處理配置值的改變煌抒。
通過Application傳遞數(shù)據(jù)
假如有個Activity A仍劈,跳轉(zhuǎn)到Activity B,并需要推薦一些數(shù)據(jù),通常的作法是Intent.putExtra()讓Intent攜帶寡壮,或者有個Bundle把信息加入Bundle讓Intent推薦Bundle對象贩疙,實現(xiàn)傳遞。但這樣做有個問題况既,Intent和Bundle所能攜帶的數(shù)據(jù)類型都是一些基本數(shù)據(jù)類型这溅,如果類型復(fù)雜的數(shù)據(jù)傳遞就比較麻煩了,通常需要實現(xiàn)Serializable或者Parcellable接口棒仍。這其實是Activit的一種IPC數(shù)據(jù)傳遞的方法悲靴。如果我們的兩個Acitivity在同一進(jìn)程中,只需要傳遞對象的引用就可以了莫其。
在Application中創(chuàng)建一個HashMap癞尚,以字符串為索引,Object為value這樣我們的HashMap可以存儲任意類型的對象了乱陡。在Activity A中把需要傳遞的對象放入這個HashMap浇揩,然后通過Intent或者其他途徑再把這所以的字符串傳遞給Activity B,ActivityB就可以根據(jù)這個字符串在HashMap中取出這個對象憨颠,只要再向下轉(zhuǎn)個型就實現(xiàn)了對象的傳遞临燃。
Application數(shù)據(jù)緩存
在Application中建立兩個HashMap一個用于數(shù)據(jù)的傳遞一個用于緩存數(shù)據(jù)。比如有一個Activity需要從網(wǎng)站中獲取一些數(shù)據(jù)烙心,獲取完了之后我們就可以吧這個數(shù)據(jù)cache到Application中,當(dāng)頁面設(shè)置到其他Activity再回來的時候就可以直接實用緩存好的數(shù)據(jù)了乏沸。但如果需要cache一些大量的數(shù)據(jù)淫茵,最好是cache一些(軟引用)SoftReference,并把這些數(shù)據(jù)cache到本地rom上或者sd卡上蹬跃。如果在application中的緩存不存在匙瘪,從本地緩存查找铆铆,如果本地數(shù)據(jù)也不存在再從網(wǎng)上獲取。使用application如果保存了一些不該保存的對象很容易導(dǎo)致內(nèi)存泄漏丹喻。如果在Application的onCreate中執(zhí)行比較耗時的操作薄货,將直接影響啟動的時間。一些清理工作不能依靠onTerminate完成碍论,因為android會盡量讓你的程序一直運行谅猾,所以很有可能onTerminate不會調(diào)用。
在Java中內(nèi)存泄漏是指鳍悠,某個或者某些對象已經(jīng)不再被使用應(yīng)該被gc回收税娜,但有個對象一直持有這個對象的引用而阻止其被回收。比如說TextView tv=new Textview(this)藏研;這里的this通常指的是Activity敬矩。所以這個TextView就持有這個引用。通常蠢挡,當(dāng)我們轉(zhuǎn)動手機(jī)的時候弧岳,Android會重新調(diào)用onCreate()方法生成一個新的Activity,原來的Activity就被gc回收业踏。但如果有個對象比如一個view的作用域超過了這個Activity(比如有一個static對象或者我們把這個View的引用放到了Application中)禽炬,這個時候原來的Activity不能被gc回收,Activity本身又持有很多對象的引用堡称,所以整個Activity的內(nèi)存被泄漏了瞎抛。
通常導(dǎo)致內(nèi)存泄漏核心原因
keeping a long-lived reference to a Context.持有一個Context的對象,從而gc不能回收却紧。
情況如下:? ? ? ?
(1)一個View的作用域超出了所在的Activity的作用域(比如一個static的View或者把一個View cache到了application當(dāng)中etc桐臊。)注意靜態(tài)的數(shù)據(jù)和緩存中的數(shù)據(jù);以及數(shù)據(jù)釋放晓殊;
(2)某些與view關(guān)聯(lián)的Drawable的作用域超出了Activity的作用域断凶。
(3)Runnable對象:比如在一個Activity中啟用了一個新線程去執(zhí)行一個任務(wù),在這期間這個Activity被系統(tǒng)回收了巫俺,但Runnable的任務(wù)還沒有執(zhí)行完畢并持有Activity的引用而泄漏认烁,但這種泄漏一般一堆時間,只有Runable的線程執(zhí)行完畢介汹,這個Activity又可以被正橙次耍回收了。
(4)內(nèi)部類的對象作用域超出了Activity的范圍:比如定義了一個內(nèi)部類來存儲數(shù)據(jù)嘹承,有把這個內(nèi)部類的對象又傳給了其他Activity和Service等窗价。因為內(nèi)部類的對象會持有這個類的引用,所以也就持有了context的引用叹卷。解決方法是如果不需要當(dāng)前的引用把內(nèi)部類寫成static或者把內(nèi)部類抽取出來變成一個單獨的類撼港,或者把避免內(nèi)部對象作用域超出Activity的作用域坪它。
Out Of Memery Error:在Android中每個程序所分到的內(nèi)存大小是有限的,如果超出這個數(shù)就誰報Out Of Mermory Error帝牡。Android給程序分配的內(nèi)存大小與手機(jī)硬件有關(guān)往毡,以下是一些手機(jī)的數(shù)據(jù):G1:16M? Droid:24M Nexus One 32M? Xoom:48M。所以盡量把程序中的一些大的數(shù)據(jù)cache到本地文件靶溜,以免內(nèi)存泄漏开瞭。
記得數(shù)據(jù)傳遞完成之后,把存放在Application的HashMap中的數(shù)據(jù)remove掉墨技,以免發(fā)生內(nèi)存泄漏惩阶。
Application被殺死的情況分析
為了決定在內(nèi)存較低的時候殺掉那個進(jìn)程,Android會根據(jù)運行在這些進(jìn)程內(nèi)的組件以及他們的狀態(tài)把進(jìn)程劃分成一個“重要程度層次”扣汪,其重要程度按以下規(guī)則排序:
1:前端進(jìn)程可以是一個持有運行在屏幕最前端并與用戶交互的Activity的進(jìn)程(onResume方法被調(diào)用時)断楷,也可以是持有一個正在運行的IntertReceiver(也就是說它正在執(zhí)行自己的onReceiverInrent方法)的進(jìn)程。在系統(tǒng)中崭别,只會有少數(shù)這樣的進(jìn)程冬筒,并且除非內(nèi)存已經(jīng)低到不夠這些進(jìn)程運行,否則系統(tǒng)不會主動殺死這些進(jìn)程茅主。這時舞痰,設(shè)備通常已經(jīng)達(dá)到了需要內(nèi)存整理的狀態(tài),所以殺掉這些進(jìn)程時為了不讓用戶界面停止響應(yīng)诀姚。
2:可視進(jìn)程是持有一個被用戶可見响牛,但沒有顯示在最前端(onPause方法被調(diào)用時)的Activity的進(jìn)程。舉例來說赫段,這種進(jìn)程通常出現(xiàn)在一個前端Activity以一個對話框出現(xiàn)并保持前一個Activity可見時呀打,這種進(jìn)程被系統(tǒng)認(rèn)為是極其重要的,并且通常不會被殺掉糯笙,除非為了保持所有前端進(jìn)程正常運行不得不殺死這些可見進(jìn)程贬丛。
3:服務(wù)進(jìn)程是持有一個Service的進(jìn)程,該Service是由startService()方法啟動的给涕,盡管這些進(jìn)程用戶不能直接看到豺憔,但它們做的工作用戶是十分關(guān)注的(例如,在后臺播放mp3或是在后臺下載上傳文件)够庙,所以恭应,除非為了保持所有的前端進(jìn)程和可視進(jìn)程正常運行外,系統(tǒng)是不會殺掉服務(wù)進(jìn)程的耘眨。
4:后臺進(jìn)程是持有一個不再被用戶可見的Activity(onStop()方法被調(diào)用時)的進(jìn)程暮屡。這些進(jìn)程不會直接影響用戶體驗,加上這些進(jìn)程已經(jīng)完整的毅桃,正確的完成了自己的生命周期(訪問Activity查看跟多細(xì)節(jié))褒纲,系統(tǒng)會在為前三種進(jìn)程釋放內(nèi)存時隨時殺掉這些后臺進(jìn)程。通常會有很多的后臺進(jìn)程在運行钥飞,所以這些進(jìn)程被存放在一個LRU列表中莺掠,以保證在低內(nèi)存的時候,最近一個被用戶看到的進(jìn)程最后被殺掉读宙。
5:空進(jìn)程時沒有持有任何活動應(yīng)用組件的進(jìn)程彻秆,保留這種進(jìn)程的唯一理由時為了提供一種緩存機(jī)制,縮短他的應(yīng)用下次運行時的啟動時間结闸,就本身而言唇兑,系統(tǒng)殺掉這些進(jìn)程的目的時為了在這些空進(jìn)程和底層的核心緩存之間平衡整個系統(tǒng)的資源。
當(dāng)需要給一個進(jìn)程分類的時候桦锄,系統(tǒng)會在該進(jìn)程中處于活動狀態(tài)的所有組件里掉選一個重要等級最高作為分類依據(jù)扎附。查看Activity,Service结耀,IntentReceiver的文檔留夜,了解每個組件在進(jìn)程整個生命周期中的貢獻(xiàn)。每一個classes 的文檔詳細(xì)描述它們在各自應(yīng)用的生命周期中所起的作用图甜。
Application的context
1碍粥,他描述的時一個應(yīng)用程序環(huán)境的信息,即上下文
2黑毅,該類是一個抽象(abstract class)類嚼摩,Android提供了該抽象類的具體實現(xiàn)類(ContextIml)
3,通過它我們可以獲取應(yīng)用程序的資源和類矿瘦,也包括一些應(yīng)用級別操作枕面,例如:啟動一個Activity,發(fā)送廣播匪凡,接受Intent信息等
getContext()膊畴、getApplication()、getApplicationContext病游、getActivity()的區(qū)別:
(1) getContext()? ? ? 獲取到當(dāng)前對象的上下文
(2)getApplication()? 獲取Application的對象
(3)getApplicationContext()? 獲取到當(dāng)前應(yīng)用程序的上下文衰倦。生命周期隨著應(yīng)用程序的銷毀而銷毀,每個Activity都有自己的上下文辐宾,而整個應(yīng)用只有一個上下文刁笙。
(4)getActivity()? ? ? ? 獲取Acitivty對象