一,理解聲明周期
當用戶導航,退出,返回時,activity的實例在生命周期中經歷不同的狀態。Activity類提供了一系列回調方法:系統創建,停止,運行activity或者毀滅進程。
在生命周期回調方法內,你可以定義你的activity應該如何表現,當用戶離開和再次進入activity時。例如,如果你正在創建一個流媒體視頻播放器,你可能暫停再設個視頻和終止網絡連接當用戶轉到另一個app。當用戶再次返回的時候,你可以重新連接到網絡和從上個返回點打開的視頻。換句話說,每一個回調方法都能執行特定的工作,來適應不同的變化狀態。在正確的時間處理正確的工作和合理的處理不同狀態的過渡,使應用程序更加的健壯。例如,生命周期回調方法好的實現可以幫助你的app避免以下的一些錯誤
- 當使用你的app接受一個電話或者轉到另一個app,程序崩潰
- 當用戶不積極使用一些資源的時候,消耗合理的系統資源,
- 離開你的app再次返回,丟失進度
- 屏幕在橫向和縱向之間轉換時,崩潰和丟失進度。
這個文檔在細節上解釋了生命周期。通過描述生命周期模式開始這分文檔。接下來,將會解釋每一個回調方法:當他們執行時什么會發生,並且你應該實現什么在他們之間。簡單的介紹這些activity狀態和進程易被系統殺死的脆弱性之間的關系。最后,討論一些在進程之間過渡的話題。
二,聲明周期的概念
為了導航不同activity狀態之間的過渡,activity的類提供了一些核心回調方法,一共有六個:onCreate(), onStart(),onResume(), onPause(), onStop(), destory().。當activity進入一個新狀態的時候,系統會調用他們。
當用戶離開activity時,系統會調用相應的方法進行處理。在一些情況下,activity會進入部分的毀滅(文檔是這樣說的,可能這個英文理解意思有點誤差,做了少量修改,大體意思不變)。Activity仍然運行在內存中,仍然可以返回到之前的窗口。如果用戶返回這個activity,activity將會從離開的地方開始運行。系統殺死一個進程的可能性取決於當前activity的狀態。后面會介紹activity狀態和從內存中彈出之間關系(從內存彈出,不久殺死進程了嗎)
了解這些狀態之間的轉化,對如何處理你的app之間的狀態轉化,有很大的好處。
三,周期回調
注:寫一下剛才對生命周期回調方法的測試小點。
- 1. 當按下Home鍵的時,是不會destroy的,只會stop,在后台運行。當按下back的時候,會destroy
- 2. 當你主動按下back鍵時,是不會調用saveInstanceState方法,saveInstanceState方法是在onPause方法后調用。
- 3. 當按下back時,例如,從activity1返回到activity2,一般當前activity1會先調用onPause方法,再調用退回的activity2的onRestart—>onStartàonResume,然后再調用activity1的onStopàonDestroy
- 4. 就先這些解惑。
這一部分提供了概念性的信息和實現信息關於這些回調方法,被用在生命周期中。
有一些部分,例如調用SetContentView(),在他們的生命周期方法中去調用。然而,實現一個依賴組件的代碼應該放在組件它自身中。為了實現這些,你必須讓依賴組件實現生命周期意識:ttps://developer.android.google.cn/topic/libraries/architecture/lifecycle.html

- 1. onCreate()
你必須實現這個回調方法,當系統第一次創建這個activity的時候會調用它。當activity被創建的時候,進入到被創建的狀態。在onCreate()方法中,執行基礎的啟動邏輯,這些邏輯代碼只會發生一次在整個activity生命周期中。例如,實現綁定list數據,用viewModel把activity關聯起來,實例化一些類變量。這個方法接受一個形參,savedInstanceState,這是一個Bundle對象,包含activity之前的狀態。如果activity在此之前不存在,這個Bundle是空的。
如果你有一個生命周期意識的組件(有生命周期回調方法的組件),和你的activity相關聯,那么將會接受一個ON_CREATE事件(自己查,我也看不懂)。用@onLifecycleEvent注解的方法會被調用,於是你的有生命周期意識的組件將會執行任何創建狀態需要的設置代碼,
下面有一個onCreate方法的例子展示了基礎的設置代碼,例如聲明用戶接口(xml文件),定義成員變量,配置一些UI。在下面的例子中,xml布局文件通過ID被指定到setContentView中。
TextView mTextView;
// some transient state for the activity instance
String mGameState;
@Override
public void onCreate(Bundle savedInstanceState) {
// call the super class onCreate to complete the creation of activity like
// the view hierarchy
super.onCreate(savedInstanceState);
// recovering the instance state
if (savedInstanceState != null) {
mGameState = savedInstanceState.getString(GAME_STATE_KEY);
}
// set the user interface layout for this activity
// the layout file is defined in the project res/layout/main_activity.xml file
setContentView(R.layout.main_activity);
// initialize member TextView so we can manipulate it later
mTextView = (TextView) findViewById(R.id.text_view);
}
// This callback is called only when there is a saved instance that is previously saved by using
// onSaveInstanceState(). We restore some state in onCreate(), while we can optionally restore
// other state here, possibly usable after onStart() has completed.
// The savedInstanceState Bundle is same as the one used in onCreate().
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
mTextView.setText(savedInstanceState.getString(TEXT_VIEW_KEY));
}
// invoked when the activity may be temporarily destroyed, save the instance state here
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putString(GAME_STATE_KEY, mGameState);
outState.putString(TEXT_VIEW_KEY, mTextView.getText());
// call superclass to save any view hierarchy
super.onSaveInstanceState(outState);
}
還有另外一種方式定義xml布局文件。你可以創建一個view對象,通過把view對象插入viewGroup創建一個view層次結構。然后傳遞根viewGroup到setContentView中。
這里說一下三種設置contentView的方式:
1. 直接傳入一個View對象。
2 直接傳入一個layout資源ID
3 使用View.inflate方法創建一個View,傳入setContentView
- 2. onStart()
當activity進入開始狀態時,系統調用這個回調方法。這個方法將會讓activity變得用戶可見,app會准備進入前端和變得可交互。例如,這個方法初始化維護UI的代碼。
當activity到達開始狀態,任何有生命周期意識的組件會和activity的生命周期聯系到一起,同時接受一個ON_START事件。
這個狀態會完成的十分快,不會保留太長時間。
- 3. OnResume()
當activity進入到這個運行狀態,它涉及到前端,系統會調用onResume回調方法。在這個狀態中用戶會和app進行交互。當焦點從這個app離開時,才會從這個狀態停止。例如,一個電話打進來,用戶被引導到另一個app,或者設備屏幕關掉了。
當activity到達運行狀態,任何有生命周期意識的組件會和activity的生命周期聯系到一起,同時接受一個ON_Resume事件。這個方法中,生命周期組件可以啟動任何在前端運行的功能。例如開啟一個相機預覽。
注:
這一部分省略,好像設計到androidX的知識,接受的on_resume是lifecycleowner中的常量,用來處理事件的,我功力不夠,解釋不了,等我明白了再說吧。
當一個中斷發生,activity會進入暫停狀態,系統會調用onPause()。
如果activity從暫停狀態返回到運行狀態,會再一次調用onResume()方法。因此,、你應該在onResume方法中初始化你在onPause方法中釋放的組件,並且實現當進入運行狀態時必須實現的功能。
在多窗口模式中,你的Activity在pause狀態是可能完全可見的。例如在多窗口模式中,用戶點擊另一個窗口,焦點會跳轉到另一個活動中,你的活動就會處於pause狀態(在多窗口中,一般用frame實現,比如,左邊一個文章列表,右邊顯示文章內容)。這理由多窗口模式的章節。https://developer.android.google.cn/guide/topics/ui/multi-window.html
在生命周期方法中初始化資源一定要在相應的生命周期方法中進行釋放。
關於如何處理生命周期用生命周期意識組件::https://developer.android.google.cn/topic/libraries/architecture/lifecycle.html
- 4. OnPause()
當用戶有離開這個activity跡象的時候,系統會調用這個方法(經歷這個生命周 期過程不意味着activity正在毀滅)而是意味着activity不再是位於前端(在多窗口模式下它可能仍然可見)。當處於這個狀態,利用onPause方法去暫停或者調整那些不應該繼續或應適度的繼續的操作,你期望這些操作能夠短暫的運行。有幾個原因進入到這個狀態:
- 中斷發生,這是最常見的情況
- 在android 7.0(API 24)或者更高的版本,多個app運行在多窗口模式中。因為只有一個app在某一時刻擁有焦點,系統會暫停其它app
- 一個半透明的活動發生,例如dialog。只要是部分可見,他就會處於暫停。
當activity到達暫停狀態,
onPause方法運行是十分的簡介,不必花費太多的時間去執行存儲操作。由於這個原因,你不應該做一些存儲應用和用戶數據的操作,網絡連接 ,數據庫交互。那樣的工作可能在onPause方法完成前都不一定做完。你應該在onStop中做一些繁重的加載關閉操作。下面會做一些說明。
完成onPause方法,也不意味着activity會離開這個狀態,而是,這個activity會繼續保持這個狀態,直到activity再次運行或者完全的對用戶不可見。如果activity運行,系統會再次調用onReume方法。,系統會把activity實例保留在內存中,如果activity從pause狀態返回到resume狀態,當系統調onResume方法時,會再次調用activity實例。在這個場景中,你不需要再次初始化組件。如果組件變得完全不可見,系統會調用onStop方法。
- 5. onStop()
activity對用戶完全不可見,就會進入stop狀態,系統會調用onStop方法。例如,當一個新啟動的activity完全覆蓋整個屏幕。當activity終止運行時候也會調用。
在這個onStop方法中,app應該釋放或者調整不需要的資源。例如,你的app暫停動畫播放或者縮小你當前的地圖位置。利用onStop方法而不是onPause方法確保與UI相關的工作繼續,甚至是在當用戶在多窗口中瀏覽你的activity。
你應該利用onStop去存儲持久化數據。
- 6. onDestory()
在activity被消滅之前調用。調用它的原因:
- 1. 調用了finish方法
- 2. 配置改變,例如屏幕旋轉
四 activity狀態從內存釋放
當系統需要內存的時候,會把進程殺死。系統殺死一個進程依靠進程當前的狀態。而進程的狀態依靠activity的狀態。Tabel1展示了在進程狀態,activity狀態和殺死進程的可能性之間的關系。

系統不會直接的結束activity去釋放內存,系統會直接殺死運行activity的進程。
用戶可利用settings下的應用管理器殺死進程來結束app的運行。
五,存儲和恢復臨時的UI狀態
當配置改變的時候,用戶期望保留activity的UI狀態,例如屏幕方向改變和轉換到多窗口模式。在默認情況下,當配置改變的時候,系統會銷毀activity存儲的UI狀態。而用戶期望保留UI狀態,當從一個activity轉換到另一個activity。然而,系統可能會銷毀你的應用進程當用戶離開並且你的activity是stop的時候
當activity被毀滅的時候由於系統的限制,你應該結合ViewModel和onSaveInstanceStart,或者當地存儲來保存那些臨時UI狀態。如果想要了解更多的知識,可以看這個 網站:https://developer.android.google.cn/topic/libraries/architecture/saving-states.htmlhttps://developer.android.google.cn/topic/libraries/architecture/saving-states.html
- 實例狀態:
在一些場景中,你的activity是被正常銷毀 的,當你按下back或者調用finish方法。當activity是被正常銷毀的,activity徹底消失的。用戶的期望和系統的行為是相匹配的,你不需要做任何多余的工作。
然而。如這個activity是由於系統內存不足的原因被銷毀的,或者配置被改變,盡管當前activity實例被銷毀,系統任然記得這個activity是存在的。如果用戶想嘗試返回這個activity,系統會創建一個新的實例,使用被保存的數據。
系統利用被保存的數據去恢復之前的實例狀態,狀態被保存在Bundle中。在默認情況下,系統使用Bundle實例存儲在你activity布局中的v每一個view的狀態(例如輸入到Edittext組件中的text值)。於是,如果你的activity實例被銷毀再被創建,layout的狀態會被自動恢復,你不需要再去寫代碼去請求保存。
Note:為了默認情況下自動恢復view的狀態,你需要為每一個view指定獨一無二的ID。通過android:id屬性指定。
一個Bundle對象不適合保存過多的數據量,因為他在主線程中請求序列化,需要消耗內存。為了保存更多數據,你應該采用結合多個方法保存數據。
- 2. 使用onSaveInstance()存儲簡單的,輕量級UI狀態
當系統在調用stop方法之前,調用onSaveInstancestate方法,你的activity可以存儲狀態信息進入bundle實例中。這個方法默認實現保存activity中的view狀態。
為了存儲額外的實例狀態信息,你必須重寫此方法,增加鍵值對到bundle對象中。如果你重寫onSaveInstanceState方法還想要實現保存view對象的狀態,你就得調用超類里面的實現。
static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
// ...
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the user's current game state
savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
Note:顯示關閉activity或者使用finish結束時不會調用onSaveInstanceState方法的
如果存儲持久化數據,你應該當你的activity在前台活動的時候找到時機去存儲他們。如果沒有合適的時機,你應該在stop回調方法中實現他們。
- 恢復UI狀態使用存儲的狀態
當你的activity在被銷毀之后重新被創建,你可以恢復存儲的數據狀態從Bundle對象(系統傳遞給你的activity的Bundle對象)。OnCreate方法和OnRestoreinstanceState方法都使用同一個Bundle,包含的實例狀態信息是一樣的(有一個迷惑點,主動退出activity,不會調用onSaveInstanceState方法,不是代表着不能使用Bundle對象存儲數據,這個我之前也很有迷惑。搞清楚就好了)
由於在onCreate方法在創建activity時會被調用,你必須先判斷Bundle對象是不是為空。如果是空的,你應該創建一個新的activity,否則就恢復之前被銷毀時存儲的數據。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // Always call the superclass first
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
// Restore value of members from saved state
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
} else {
// Probably initialize members with default values for a new instance
}
// ...
}
你也可以使用onRestoreInstaceState方法,在onStart方法之后調用。這個方法只在有被存儲數據才會調用,所以不需要檢測是不是空。
public void onRestoreInstanceState(Bundle savedInstanceState) {
// Always call the superclass so it can restore the view hierarchy
super.onRestoreInstanceState(savedInstanceState);
// Restore state members from saved instance
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}
小心:一直調用超類的onReStoreInStaceState方法,可以恢復view 的狀態。
Activity生命周期文章篇。翻譯的不好,請勿見怪,有指正之處,請多多之處,在下感激不盡。
