一,、Activity狀態(tài)
Activity有三種狀態(tài):active/running,、paused、stopped,。
1,、active/running狀態(tài),在當(dāng)前屏幕時,,即用戶可見的Activity,,位于當(dāng)前Task的棧頂。
2,、paused狀態(tài),,Activity失去焦點但對用戶依然可見。也就是說在它上面有另外一個非全屏或者透明的Activity,,并成為了當(dāng)前的焦點,。它還沒有被其他的Activity完全遮蓋住,而paused的Activity依然是alive狀態(tài)的,它保留著所有的狀態(tài)和成員信息并連接至窗口管理器,,但當(dāng)系統(tǒng)處于極低內(nèi)存的情況下,,仍然可以殺死這個Activity。
3,、stopped 狀態(tài),,當(dāng)Activity完全被另一個Activity覆蓋時,它仍然保留所有的狀態(tài)和成員信息,。但它不再被用戶可見,,所以它的窗口將被隱藏,當(dāng)其它地方需要內(nèi)存,,則系統(tǒng)經(jīng)常會殺死這個Activity,。
當(dāng)Activity是paused或者stopped狀態(tài)時,系統(tǒng)可以通過要求它結(jié)束(調(diào)用它的finish()方法)或直接殺死它的進程來將它驅(qū)出內(nèi)存,。當(dāng)它再次為用戶可見的時候,,它只能完全重新啟動并恢復(fù)至以前的狀態(tài)。
啟動并恢復(fù)至以前的狀態(tài),。
二,、為什么會有這么麻煩的狀態(tài)變化
1、手機屏幕大小有限,,只能看到有限的界面數(shù)量,,用戶需要通過Back鍵或Home鍵或其他方式切換Activity。
2,、在有手機來電時,,系統(tǒng)會優(yōu)先切換顯示電話接聽界面,。
由于上述的一些原因,,確實存在界面隨時可能發(fā)生切換的情況,最佳方式當(dāng)然不是每次都直接銷毀之前的界面,,很多時候我們也需要在回到之前界面后恢復(fù)之前的狀態(tài),。我們需要了解這些狀態(tài),當(dāng)然還包括要掌握Activity的“生命周期”等知識,,這樣就能夠在Activity發(fā)生變化時,,知其所以然,并能夠根據(jù)需求采取一定的措施,,例如切換界面時,,保存當(dāng)前的界面信息,即使其被意外殺死也能恢復(fù)之前狀態(tài),。
三,、Activity生命周期
當(dāng)一個Activity從這個狀態(tài)轉(zhuǎn)變到另一個狀態(tài)時,它被以下列protected方法所通知:
public class Activity extends ApplicationContext
{
protected void onCreate(Bundle savedInstanceState);
protected void onStart();
protected void onRestart();
protected void onResume();
protected void onPause();
protected void onStop();
protected void onDestroy();
}
1、onCreate -- 當(dāng)Activity第一次創(chuàng)建時會被調(diào)用(未被銷毀前不會被再次調(diào)用),。在這個方法中可以做一些初始化工作,,例如對創(chuàng)建新的View、獲取并設(shè)置View的一些屬性,、綁定列表的數(shù)據(jù)等等,。如果能捕獲到Activity 狀態(tài)的話,這個方法傳遞進來的Bundle對象將存放了Activity當(dāng)前的狀態(tài),。調(diào)用該方法后一般會調(diào)用onStart()方法,。此時Activity不可見,所以并不是所有的初始化工作都適合在這里做,,例如一些動畫的開始,。
2、onRestart -- 在Activity被停止后重新啟動時會調(diào)用該方法,。其后續(xù)會調(diào)用onStart方法,。
3、onStart -- 當(dāng)Activity對于用戶可見前即調(diào)用這個方法,。如果Activity回到前臺則接著調(diào)用onResume() ,,如果Activity隱藏則調(diào)用onStop()。此時Activity可能可見,,但即使可見,,也無法進行交互操作。
4,、onResume -- 在Activity開始與用戶交互前調(diào)用該方法,。在這時該Activity 處于Activity 棧的頂部,并且接受用戶的輸入,。其后續(xù)會調(diào)用 onPause() 方法,。此時Activity也不一定可見,需要通過onWindowFocusChanged(boolean)來確定Activity是否可見,。
5,、onPause -- 在系統(tǒng)開始準(zhǔn)備恢復(fù)其它Activity時會調(diào)用該方法。這個方法中通常用來提交一些還沒保存的更改到持久數(shù)據(jù)中,,停止一些動畫或其它一些耗CPU的操作等等,。無論在該方法里面進行任何操作,都需要較快速完成,,因為如果它不返回的話,,下一個Activity 將無法恢復(fù)出來。如果Activity 返回到前臺將會調(diào)用onResume(),,如果Activity變得對用戶不可見了將會調(diào)用onStop() ,。
6,、onStop -- 在Activity對用戶不可見時將調(diào)用該方法??赡軙驗楫?dāng)前Activity 正在被銷毀,,或另一個Activity(已經(jīng)存在的Activity 或新的Activity )已經(jīng)恢復(fù)了正準(zhǔn)備覆蓋它,而調(diào)用該方法,。如果Activity 正準(zhǔn)備返回與用戶交互時后續(xù)會調(diào)用onRestart ,,如果Activity正在被釋放則會調(diào)用onDestroy 。
7,、onDestroy -- 在Activity被銷毀前會調(diào)用該方法,。這是Activity能接收到的最后一個調(diào)用。可能會因為有人調(diào)用了finish方法使得當(dāng)前Activity正在關(guān)閉,,或系統(tǒng)為了保護內(nèi)存臨時釋放這個Activity的實例,,而調(diào)用該方法。你可以用isFinishing方法來區(qū)分這兩種不同的情況,。
要注意的是,,onPause(),onStop(),,onDestory()這3個方法都可能會因為系統(tǒng)內(nèi)存不足而被系統(tǒng)直接kill,。而平常從一個Activity轉(zhuǎn)向/回到另一個Activity時,當(dāng)新Activity是full screen(彈出窗口,,例如AlertDialog是不算的)的時候就會調(diào)用前一個Activity的onPause(),,然后調(diào)用onStop(),而無論onPause或者onStop,,都有可能被kill,,所以一般在onPause時就應(yīng)該保存需要持久化的一些數(shù)據(jù)(例如用戶編輯的信息)。
onCreate,、onStart,、onResume都不是Activity準(zhǔn)確能夠交互的點,真正的是onWindowFocusChaned()函數(shù)被執(zhí)行時,。
四,、Android的進程
android根據(jù)其重要性在內(nèi)存不足的時候移去重要性最低的進程,。重要性由高到低為:
1,、活動/前臺進程
指那些有組件正和用戶進行交互的應(yīng)用程序進程。他們都是android嘗試通過回收資源來使其保持響應(yīng)的進程,。這些進程的數(shù)量非常少,,只用到最后的關(guān)頭才會終止這些進
程。
活動進程包括:
處于“活動”狀態(tài)的Activity,,也就是說,,它們位于前臺并對用戶事件進行響應(yīng),。
正在執(zhí)行onReceive事件處理程序的廣播接收器。
正在執(zhí)行onCreate(),、onStart()或onDestory事件處理程序的服務(wù),。
正在運行,且已被標(biāo)記為前臺運行的服務(wù),。
2,、可見進程
可見,但是非活動的進程是指那些駐留可見活動的進程,。顧名思義,,可見的活動能被用戶看到,但是他們并不是在前臺運行或者能對用戶事件做出響應(yīng),,比如,,當(dāng)一個活動Activity被部分遮擋的時候(被一個非全屏或者半透明狀態(tài)的Activity遮擋時)就會出現(xiàn)這類情況。這類進程的數(shù)量很少,,只有在資源極度缺乏的環(huán)境下,,為保證活動進程的繼續(xù)執(zhí)行,才會終止這些進程,。
3,、服務(wù)進程
已經(jīng)啟動的服務(wù)進程。服務(wù)支持在沒有可見界面的情況下,,仍然能繼續(xù)不間斷地進行處理,。因為后臺服務(wù)沒有直接和用戶進行交互,所以它們的優(yōu)先級要比可見進程低一些,。但是他們?nèi)匀槐徽J(rèn)為是前臺進程,。除非活動或者可見進程需要資源,否則不會終止它們,。
4,、后臺進程
不可見,并且沒有任何正在運行的服務(wù)的活動的進程,,通常會有大量的后臺進程,。這樣的程序擁有一個用戶不可見的Activity。這樣的程序在系統(tǒng)內(nèi)存不足時,,按照LRU的順序被結(jié)束,。
運行著一個對用戶不可見的Activity(調(diào)用過onStop() 方法)。這些進程對用戶體驗沒有直接的影響,,可以在服務(wù)進程,、可見進程、前臺進程需要內(nèi)存的時候回收,。通常,,系統(tǒng)中會有很多不可見進程在運行,,他們被保存在LRU (least recently used) 列表中,以便內(nèi)存不足的時候被第一時間回收,。如果一個Activity正確的執(zhí)行了它的生命周期,,關(guān)閉這個進程對于用戶體驗沒有太大的影響。
5,、空進程
這樣的進程不包含任何活動的程序部件,。系統(tǒng)可能隨時關(guān)閉這類進程。未運行任何程序組件,。運行這些進程的唯一原因是作為一個緩存,,縮短下次程序需要重新使用的啟動時間。系統(tǒng)經(jīng)常中止這些進程,,這樣可以調(diào)節(jié)程序緩存和系統(tǒng)緩存的平衡,。
Android對進程的重要性評級的時候,選取它最高的級別,。另外,,當(dāng)被另外的一個進程依賴的時候,某個進程的級別可能會增高,。一個為其他進程服務(wù)的進程永遠(yuǎn)不會比被服務(wù)的進程重要級低,。因為服務(wù)進程比后臺Activity進程重要級高,因此一個要進行耗時工作的Activity最好啟動一個Service來做這個工作,,而不是開啟一個子進程――特別是這個操作需要的時間比Activity存在的時間還要長的時候,。例如,在后臺播放音樂,,向網(wǎng)上上傳攝像頭拍到的圖片,,使用Service可以使進程最少獲取到“服務(wù)進程”級別的重要級,而不用考慮Activity目前是什么狀態(tài),。broadcast receivers做費時的工作的時候,,也應(yīng)該啟用一個服務(wù)而不是開一個線程。
五,、Activity狀態(tài)的保存
protected void onSaveInstanceState (Bundle outState)
protected void onRestoreInstanceState (Bundle savedInstanceState)
onSaveInstanceState() 和 onRestoreInstanceState() 并不是生命周期方法,。它們并不是總會被調(diào)用。例如通過Back造成的銷毀Activity時,,它就不會被調(diào)用,。應(yīng)該只用它來為Activity保存一些臨時的狀態(tài),而不能用來保存持久性的數(shù)據(jù),。而是應(yīng)該用onPause()來達(dá)到這個目的,。
onPause()方法是在系統(tǒng)結(jié)束應(yīng)用程序前調(diào)用的最后一個安全的方法。無法保證onStop和onDestroy會被調(diào)用,,所以不能依賴這兩個方法來實現(xiàn)關(guān)鍵邏輯,。
六、Activity的加載模式
Activity加載模式(通過在AndroidManifest.xml文件中activity元素的android:launcherMode屬性設(shè)置) ,。請參考文章結(jié)尾附帶的demo體驗Activity的加載模式,。
1、standard(默認(rèn))
測試方式:MainActivity(standard),,SecondActivity(standard)
每次都是創(chuàng)建了新的Activity實例,。
2、singleTop
測試方式:MainActivity(singTop),,MainActivity自己intent自己
測試方式:MainActivity(singleTop),,SecondActivity(standard)
和standard一樣是發(fā)送新的實例,但singleTop要求如果創(chuàng)建intent的時候棧頂已經(jīng)有要創(chuàng)建的Activity實例,,則將intent發(fā)送給該實例,。例如給MainActivity設(shè)置singleTop,然后按鈕也是intent自己,,那么會發(fā)現(xiàn)一直都是MainActivity當(dāng)前這個實例,,因為他一直在棧頂,所以不會創(chuàng)建新的,。
如果用A打開B,,而B再打開A,如此循環(huán),,如果A是設(shè)置了singleTop,,B是默認(rèn),則每次A都是新的,,因為每次要打開A時,,棧頂都不是A,就要創(chuàng)建新的A實例(和都是 standard沒啥區(qū)別了),。
此種模式的應(yīng)用場景,,目前想到就是為了解決自己在棧頂時,自己給自己發(fā)送intent可以不創(chuàng)建新的實例,。實際中應(yīng)用的也較少,。
3、singleTask
測試方式:MainActivity(singleTask),,SecondActivity(standard)
只創(chuàng)建一個實例,。如果發(fā)現(xiàn)有對應(yīng)的Activity實例,則是此Activity實例之上的其他Activity實例全部出棧,,使此Activity實例成為棧頂對象,,顯示出來。
4,、singleInstance
這個模式下的Activity單獨在一個task棧中,。這個棧只有一個Activity,。目的是為了多個Task共享一個Activity。
七,、Activity與View的生命周期
View和Activity一樣也有自己的生命周期,,具體在View的周期中包含哪些通知函數(shù),參見http://developer./reference/android/view/View.html,。其中onMeasure,、onLayout、onDraw最重要,,而onMeasure最難理解(之后會單獨討論這個函數(shù)及其如何使用),。
八、Activity的注意事項
1,、onConfigurationChanged
1)不設(shè)置Activity的android:conChanges時,,切屏?xí)匦抡{(diào)用各個生命周期,切橫屏?xí)r會執(zhí)行一次,,切豎屏?xí)r會執(zhí)行兩次,。
2)設(shè)置Activity的android:configChanges=”orientation”時,切屏還是會重新調(diào)用各個生命周期,,切橫,、豎屏?xí)r只會執(zhí)行一次。
3)設(shè)置Activity的android:configChanges=”orientation|keyboardHidden”時,,切屏不會重新調(diào)用各個生命周期,,只會執(zhí)行重寫的onConfigurationChanged方法。
在實際開發(fā)中,,我們會因為生命周期的一些奇怪現(xiàn)象而接觸到這個函數(shù),。例如http://www.cnblogs.com/endure/p/3416736.html
九、參考文章
http://blog.csdn.net/liuhe688/article/details/6754323