想要徹底弄清楚Activity在不同情況下的生命周期需要先掌握Activity的一些基礎知識
Activity完整的生命周期如下圖:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2Lc1TRE1EeBpHZ1A3MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2LcRHelR3LcJzLctmch1mclRXY39DO0IzMwUDNxIjMyQDM4EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
知道了Activity完整的生命周期之後還需要知道Activity的啟動模式。
Activity四種啟動模式:
-
standard:
預設的啟動模式,每次通過這種模式啟動目标Acitivity,都建立一個新的執行個體,并将該Activity添加到目前棧頂。
-
singleTop:
隻有當Activity位于棧頂時,系統才不會重新建立目标Activity的執行個體,而是直接複用已有的Activity執行個體。否則建立一個新的執行個體。這種模式經常被用在新聞展示頁,當推送過來一條新聞,跳轉到新聞頁顯示,如果你正在看新聞,就不需要重複的建立這個activity
-
singleTask:
如果棧中不存在目标Activity時,則建立目标Activity執行個體。
如果棧中存在目标Activity時,
(1)已經位于棧頂,此時與singleTop行為相同
(2)不位于棧頂,系統會使該Activity上面所有的Activity出棧。
-
singleInstance:
如果棧中不存在目标Activity,系統會建立一個新的任務棧,再建立Activity執行個體,将它加入該棧中
如果棧中存在該Activity,無論哪個應用程式調用,都不會建立新的Activity
舉例
假設有兩個Activity A、B
-
standard模式
當A啟動到從A跳轉到B的生命周期
A啟動時:onCreate -> onStart -> onResume
從A跳轉到B時:A.onPause -> B.onCreate -> onStart -> onResume -> A.onStop
按back鍵傳回時:B.onPause -> A.onReStart -> onStart -> onResume -> B.onStop -> onDestroy
-
singleTop模式
設定A為singleTop,啟動A,從A跳A,就是在棧頂時會不會建立A的執行個體
A啟動時:onCreate -> onStart -> onResume
從A跳A時:onPause -> onResume
按back鍵傳回時:onPause -> onStop -> onDestroy
可以看到并沒有重新建立A的執行個體,隻是執行了onPause 和onResume
-
singleTask模式
設定A為singleTask,啟動A,從A跳B,再從B跳A
A啟動時:onCreate -> onStart -> onResume
從A跳轉到B時:A.onPause -> B.onCreate -> onStart -> onResume -> A.onStop
從B跳轉到A時:B.onPause -> A.onReStart -> onStart -> onResume -> B.onStop -> onDestroy
可以看到當A在棧中存在時,再次跳轉不會建立A的執行個體并使A上面的B出棧
-
為 singleInstance 模式時,activity獨占一個task,現在有以下三個activity: Act1、Act2、Act3,其中Acti2 為 singleInstance 模式。它們之間的跳轉關系為: Act1 – Act2 – Act3 ,現在在Act3中按下傳回鍵,由于Act2位于一個獨立的task中,它不屬于Act3的上下文activity,是以此時将直接傳回到Act1,Act1再按下傳回鍵時到Act2,這就是singleInstance模式。singleInstance模式
看完四種模式,這裡會有疑問:
為什麼要先執行A的onPause方法,再執行B的生命周期方法?
為什麼不是執行完A的onStop方法之後再執行B的生命周期方法?
首先來看第一個問題,假如A正在播放一段音樂,如果先執行B的生命周期,再執行A的onPause方法,就會出現B已經顯示出來,A中的音樂還在播放的異常情況。而如果先執行了A的onPause方法,我們就可以在其中執行一些操作來暫停音樂的播放。原本onPause方法的設計職責即使如此。
對于第二個問題,由于Activity的可見生命周期是onStart()到onStop(),假如先執行A的onPause()和onStop(),再執行B的生命周期,每次切換的時候就會出現黑屏的情況,這種切換效果顯然是不優雅的。
注:
- 建議在onCreate()中調用setContentView()、findViewById()
- 建議在onResume()中打開獨占裝置(比如相機)、開啟動畫等
- 建議在onPause()中執行關閉獨占裝置、停止動畫等比較耗CPU的操作,但不要執行比較耗時的操作,底層執行Activity的onPause()時,有一定的時間限制的,當ActivityManagerService通知應用程序暫停指定的Activity時,如果對應的onPause()在500ms内還沒有執行完,ActivityManagerService就會強制關閉這個Activity。
- onStop()中可以執行一些比較耗時的操作,這是在背景執行是以也不影響使用者的體驗
附:
伴随着activity常用的除了生命周期還有兩個方法,onSaveInstanceState 和 onNewIntent
1.onSaveInstanceState
我們都知道不同的手機,記憶體不同,系統在記憶體不足的時候很有可能就會把你APP中不再棧頂的activity給回收掉。如果這個activity無關緊要那就啥也不說了,但是就怕它對你來說很重要。這個時候你不對它進行保護措施的話,你就等着哭吧。比如你打開了A,A是一個注冊類activity。然後你填寫了一堆資訊後,傳回桌面去看了一條短信,或者接了一個電話,等你再打開這個的時候你發現裡面填寫的東西都不見了,這個時候你想不想一巴掌拍死這個開發人員?
是以呢onsaveinstancestate()就可以閃亮登場了,雖然你也可以使用其他儲存機制去處理,但是對于這種情況,onsaveinstancestate()依然是最佳的選擇。onsaveinstancestate()方法有的同學有可能沒見過 但是savedinstancestate相必都見過,就是在oncreate()方法的那個括号裡面,savedinstancestate是一個bundle類型的參數,bundle有很多儲存資料的方法這個你想必是知道的吧,對我們就是利用這個去儲存資料。onsaveinstancestate()回調方法會保證一定在activity被回收之前調用
onSaveInstanceState方法會在什麼時候被執行,有這麼幾種情況:
- 當使用者按下HOME鍵時。
- 長按HOME鍵,選擇運作其他的程式時。
- 按下電源按鍵(關閉螢幕顯示)時。
- 從activity A中啟動一個新的activity時。
- 螢幕方向切換時,例如從豎屏切換到橫屏時。
當按下HOME鍵或者鎖屏時,會執行onPause -> onSaveInstanceState -> onStop
當從activity A跳轉到 B 時,A.onPause -> B.onCreate -> onStart -> onResume -> A.onSaveInstanceState -> A.onStop
使用:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_one);
if (savedInstanceState != null) {
String oldString = savedInstanceState.getString("Activity");
Log.e(TAG,"oldString="+oldString);
}
Log.e(TAG,"onCreate");
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.e(TAG,"onSaveInstanceState");
String string = "activity 被系統回收了怎麼辦?";
outState.putString("Activity", string);
}
2.onNewIntent
如果activity設定為singleTask或者signleTop模式【當調用startActivity方法時,這兩種模式不會重新建立activity,隻會調用onNewIntent方法,當然任務棧中沒有銷毀該activity的情況下】,再向activity傳值時,就可以利用onNewIntent
執行順序:onNewIntent -> onReStart -> onStart -> onResume
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.e(TAG,"onNewIntent");
setIntent(intent);
String msg = getIntent().getExtras().getString("msg");
Log.e(TAG,"msg="+msg);
}
//另一個activity中發送
Intent intent = new Intent(this,OneActivity.class);
intent.putExtra("msg","傳值過來");
startActivity(intent);