Activity的生命周期很重要骤菠,掌握好Activity的生命周期畅厢,應用程序才會擁有好的用戶體驗
返回棧
Android的Activity是可以重疊的欲鹏。每啟動一個新的Activity暴凑,就會覆蓋在原Activity之上如绸,然后點擊Back鍵就會銷毀最上面的Activity完域,下面的Activity就會重新顯示出來软吐。
Android是使用任務(Task)來管理Activity的,一個任務就是一組放在棧里的Activity的集合吟税,這個棧也被稱作返回棧(Back stack)凹耙。棧是一種后進先出的數(shù)據(jù)結(jié)構(gòu)姿现,默認情況下,每當啟動了一個新的Activity肖抱,它會在返回棧中入棧备典,并處于棧頂位置。當按下Back鍵或調(diào)用finish()方法去銷毀一個Activity時意述,處于棧頂?shù)腁ctivity會出棧熊经,這時前一個入棧的Activity就會重新處于棧頂位置,系統(tǒng)就會顯示處于棧頂?shù)腁ctivity給用戶欲险。
Activity狀態(tài)
每個Activity在其生命周期中最多可能會有4種狀態(tài)
- 運行狀態(tài)
當一個Activity位于返回棧的棧頂時镐依,這時Activity就處于運行狀態(tài),系統(tǒng)最不愿意回收處于運行狀態(tài)的Activity天试,這會帶來很差的用戶體驗
- 暫停狀態(tài)
當一個Activity不再處于棧頂位置槐壳,但仍然可見,這時Activity就進入了暫停狀態(tài)喜每。既然不在棧頂了务唐,那為什么還能可見呢?這是因為并不是每一個Activity都會占滿整個屏幕带兜,比如對話框形式的Activity只會占用屏幕中間的部分區(qū)域枫笛。處于暫停狀態(tài)的Activity仍然是完全存貨的,系統(tǒng)也不愿意回收這種Activity刚照,只有在內(nèi)存較低的情況下刑巧,系統(tǒng)才會去考慮回收這種Activity
- 停止狀態(tài)
當一個Activity不在棧頂并且也完全不可見的時候,就進入了停止狀態(tài)无畔。系統(tǒng)仍然會為這種Activity保存相應的狀態(tài)和成員變量啊楚,但是這并不是完全可靠的,當其他地方需要內(nèi)存時浑彰,處于停止狀態(tài)的Activity有可能被系統(tǒng)回收
- 銷毀狀態(tài)
當一個Activity從返回棧中移除后就變成了銷毀狀態(tài)恭理。系統(tǒng)最傾向于回收處于這種狀態(tài)的Activity,以保證手機的內(nèi)存充足
Activity的生存期
Activity類中定義了7個回調(diào)方法郭变,覆蓋了Activity生命周期的每個環(huán)節(jié)
-
onCreate()
.每個Activity中都需要重寫這個方法颜价,它會在Activity第一次創(chuàng)建的時候調(diào)用。應該在這個方法中完成Activity的初始化操作诉濒,如家在布局周伦、綁定事件等 -
onStart()
.這個方法在Activity由不可見變?yōu)榭梢姷臅r候調(diào)用 -
onResume()
.這個方法在Activity準備好和用戶進行交互的時候調(diào)用。此時的Activity已定位于返回棧的棧頂循诉,并且處于運行狀態(tài) -
onPause()
.這個方法在系統(tǒng)準備去啟動或者恢復另一個活動的時候調(diào)用横辆。通常會在這個方法中將一些消耗CPU的資源釋放掉,以及保存一些關鍵數(shù)據(jù),但這個方法的執(zhí)行速度一定要快狈蚤,不然會影響到新的棧頂Activity的活動困肩。 -
onStop()
.這個方法在Activity完全不可見的時候調(diào)用。它和onPause()
方法的主要區(qū)別在于脆侮,如果啟動的新Activity是一個對話框式的Activity锌畸,那么onPause()
方法會得到執(zhí)行,而onStop()
方法并不會執(zhí)行靖避。 -
onDestroy()
.這個方法在Activity被銷毀之前調(diào)用潭枣,之后Activity的狀態(tài)編程銷毀狀態(tài) -
onRestart()
.這個方法在Activity由停止狀態(tài)變?yōu)檫\行狀態(tài)之前調(diào)用,也就是Activity被重新啟動了
以上除了onRestart()
方法幻捏,其他的都是兩兩相對的盆犁,從而又可以將Activity分為3種生存期
- 完整生存期。Activity在
onCreate()
方法和onDestroy()
方法之間所經(jīng)歷的篡九,就是完整生存期谐岁。一般情況下,一個Activity會在onCreate()
方法中完成各種初始化操作榛臼,而在onDestroy()
方法中完成釋放內(nèi)存的操作伊佃。 - 可見生存期。Activity在
onStart()
方法和onStop()
方法之間所經(jīng)歷的沛善,就是可見生存期航揉。在可見生存期內(nèi),Activity對于用戶總是可見的金刁,即便有可能無法和用戶進行交互帅涂。可以通過這兩個方法胀葱,合理的管理那些對用戶可見的額資源漠秋。比如在onStart()方法中對資源的加載,而在onStop()
方法中對資源進行釋放抵屿,從而保證處于停止狀態(tài)的Activity不會占用過多內(nèi)存 - 前臺生存期。Activity在
onResume()
方法和onPause()
方法之間所經(jīng)歷的就是前臺生存期捅位。在前臺生存期內(nèi)轧葛,Activity總是處于運行狀態(tài)的,此時的Activity是可以和用戶進行交互的艇搀,平時看到和接觸最多的也就是這個狀態(tài)的Activity
體驗Activity的生命周期
Activity被收回怎么辦
當一個Activity進入了停止狀態(tài)尿扯,是有可能被系統(tǒng)回收的,下面來看一種場景:
應用中有一個Activity A焰雕,用戶在Activity A的基礎上啟動了Activity B衷笋,Activity A就進入了停止狀態(tài),這個時候由于系統(tǒng)內(nèi)存不足矩屁,把Activity A回收掉了辟宗,然后用戶按下Back返回Activity A爵赵,會出現(xiàn)什么情況呢?其實還是會正常顯示Activity A的泊脐,只不過這時并沒有執(zhí)行onRestart()
方法空幻,而是會執(zhí)行Activity A的onCreate()
方法,因為Activity A在這種情況下會被重新創(chuàng)建一次容客。
這樣看上去好像也沒什么不妥秕铛,但是如果Activity A中存在臨時數(shù)據(jù)或者狀態(tài)的話,比如Activity A中有一個文本輸入框缩挑,已經(jīng)輸入了一段文字但两,然后啟動Activity B之后,Activity A被系統(tǒng)回收供置,當你點擊Back鍵返回后由于重新走了onCreate()
方法镜遣,因此剛才輸入的內(nèi)容就沒有了,那這種情況就會影響用戶體驗士袄,因此要想辦法解決這個問題悲关。
其實在Activity中還提供了一個onSaveInstanceState()
回調(diào)方法,這個方法可以保證在活動被回收之前一定會被調(diào)用娄柳,因此可以通過這個方法解決Activity被回收時臨時數(shù)據(jù)或狀態(tài)得不到保存的問題寓辱。
onSaveInstanceState()
會攜帶一個Bundle類型的參數(shù),Bundle提供了一系列的方法用于保存數(shù)據(jù)赤拒,比如使用putString()
方法保存字符串秫筏,使用putInt()
保存整型數(shù)據(jù),以此類推挎挖。每個方法需要兩個參數(shù)这敬,第一個參數(shù)是鍵,用于后面從Bundle中取值蕉朵,另外一個參數(shù)是真正要保存的內(nèi)容崔涂。
在MainActivity中添加如下代碼將臨時數(shù)據(jù)進行保存:
// 保存臨時數(shù)據(jù)
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
String tempData = "Something you just typed";
outState.putString("data_key", tempData);
}
在onCreate()方法中也有一個Bundle類型的參數(shù),該參數(shù)一般情況下都是null始衅,但是如果在Activity被系統(tǒng)回收前有通過onSaveInstanceState()
方法來保存數(shù)據(jù)的話冷蚂,這個參數(shù)就會帶有之前所保存的所有數(shù)據(jù),只需要通過相應的取值方法將數(shù)據(jù)取出即可汛闸。
修改MainActivity中的onCreate()方法蝙茶,如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate:");
if (savedInstanceState != null) {
String tempData = savedInstanceState.getString("data_key");
Log.d(TAG, tempData);
}
}
取出值之后再做相應的恢復操作就可以了,比如說將文本內(nèi)容重新賦值到文本框中等等诸老。
使用Bundle來保存數(shù)據(jù)跟使用Intent傳遞數(shù)據(jù)類似隆夯。Intent還可以結(jié)合Bundle一起用于傳遞數(shù)據(jù),首先可以把需要傳遞的數(shù)據(jù)都保存在Bundle對象中,然后再將Bundle對象存在Intent中蹄衷,到了目標Activity之后先從Intent中取出Bundle忧额,再從Bundle中一一去處數(shù)據(jù)。