Activity 生命週期紀錄

概要:


生命週期主要包含 6 種狀態: onCreat, onStart, onResume, onPause, onStop, onDestroy。

各種狀態意義為
onCreate 代表 Activity 的建立
onStart 代表 Activity 的啟動
onResume 代表 Activity 的恢復
onPause 代表 Activity 的暫停
onStop 代表 Activity 的停止
onDestroy 代表 Activity 的銷毀

這些狀態分別互相配對,構成 3 種生命週期,分別為完整的生命週期,可視的生命週期,前台的生命週期。
完整的生命週期包含可視的生命週期,可視的生命週期包含前台的生命週期。

完整的生命週期:

Activity 從建立到銷毀的全部過程。最外層生命週期,生命週期發生在 onCreate 到 onDestroy 之間。

可視的生命週期:

Activity 從使用者可視到離開使用者視線的過程。生命週期發生在 onStart 到 onStop 之間。注意可視包含該 Activity 被其它元件遮蓋只顯示一部分的情況。

前台的生命週期:

Activity 顯示在所有的元件之前並可與使用者互動。生命週期發生在 onResume 到 onPause 之間。

另外還有 4 種特殊的生命週期狀態,各為 onRestart, onSaveInstanceState, on RestoreInstanceState, onNewIntent。

onRestart 的呼叫點為從 onStop 到 onStart 之間,也就是 onStop -> onRestart ->  onStart。

onSaveInstanceState 用於儲存 Activity 的資料。

onNewIntent 只有在 LaunchMode 為 SingleTop 且啟動的 Activity 為符合重用該 Activity 的規則時才會被呼叫。(onNewIntent -> onResume)

為了實際了解生命週期的變化,建立 FirstActivity 並覆寫所有生命週期印出 Log
FirstActivity.java
public class FirstActivity extends AppCompatActivity implements OnClickListener {  

private static final String TAG = FirstActivity.class.getSimpleName();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, TAG + " onCreate");
setContentView(R.layout.first_activity);
}

@Override
protected void onStart() {
super.onStart();
Log.d(TAG, TAG + " onStart");
}

@Override
protected void onResume() {
super.onResume();
Log.d(TAG, TAG + " onResume");
}

@Override
protected void onPause() {
super.onPause();
Log.d(TAG, TAG + " onPause");
}

@Override
protected void onStop() {
super.onStop();
Log.d(TAG, TAG + " onStop");
}

@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, TAG + " onDestroy");
}

@Override
protected void onRestart() {
super.onRestart();
Log.d(TAG, TAG + " onRestart");
}

@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.d(TAG, TAG + " onSaveInstanceState");
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.d(TAG, TAG + " onRestoreInstanceState");
}

@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.d(TAG, TAG + " onNewIntent");
}

}

 

紀錄1


使用者點擊 back key, home key, menu key 所觸發的生命週期變化:


A.啟動 FirstActivity 後點擊 back key 關閉 FirstActivity
1.點擊 App icon 啟動 FirstActivity:
D: FirstActivity onCreate
D: FirstActivity onStart
D: FirstActivity onResume
2.點擊 back key:
D: FirstActivity onPause
D: FirstActivity onStop
D: FirstActivity onDestroy

B.啟動 FirstActivity 後點擊 home key
1.點擊App icon 啟動 FirstActivity:
D: FirstActivity onCreate
D: FirstActivity onStart
D: FirstActivity onResume
2.點擊 home key:
D: FirstActivity onPause
D: FirstActivity onSaveInstanceState
D: FirstActivity onStop

C.啟動 FirstActivity 後點擊 home key 再點擊 App icon
1.點擊 App icon 啟動 FirstActivity:
D: FirstActivity onCreate
D: FirstActivity onStart
D: FirstActivity onResume
2.點擊 home key:
D: FirstActivity onPause
D: FirstActivity onSaveInstanceState
D: FirstActivity onStop
3.點擊 App icon:
D: FirstActivity onRestart
D: FirstActivity onStart
D: FirstActivity onResume

D.啟動 FirstActivity 後點擊 home key 再點擊 menu key 再拖曳移除 App頁面
1.點擊 App icon 啟動 FirstActivity:
D: FirstActivity onCreate
D: FirstActivity onStart
D: FirstActivity onResume
2.點擊 home key:
D: FirstActivity onPause
D: FirstActivity onSaveInstanceState
D: FirstActivity onStop
3.點擊 menu key,拖曳移除 App:
D: FirstActivity onDestroy(注意有時候不會顯示)

E.啟動 FirstActivit y後點擊 home key 再點擊 menu key 再點擊 App 頁面
1.點擊 App icon 啟動 FirstActivity:
D: FirstActivity onCreate
D: FirstActivity onStart
D: FirstActivity onResume
2.點擊 home key:
D: FirstActivity onPause
D: FirstActivity onSaveInstanceState
D: FirstActivity onStop
3.點擊 menu key 並點擊 App 頁面:
D: FirstActivity onRestart
D: FirstActivity onStart
D: FirstActivity onResume

F.啟動 FirstActivity後點擊 menu key
1.點擊 App icon 啟動 FirstActivity:
D: FirstActivity onCreate
D: FirstActivity onStart
D: FirstActivity onResume
2.點擊 menu key:
D: FirstActivity onPause
D: FirstActivity onSaveInstanceState
D: FirstActivity onStop

G.啟動 FirstActivity 後點擊 menu key 再拖曳移除 App
1.點擊 App icon 啟動 FirstActivity:
D: FirstActivity onCreate
D: FirstActivity onStart
D: FirstActivity onResume
2.點擊 menu key:
D: FirstActivity onPause
D: FirstActivity onSaveInstanceState
D: FirstActivity onStop
3.拖曳移除 App:
沒有顯示Log , 推測應該呼叫onDestroy

H.啟動 FirstActivity 後點擊 menu key 再點擊 App頁面
1.點擊 App icon 啟動 FirstActivity:
D: FirstActivity onCreate
D: FirstActivity onStart
D: FirstActivity onResume
2.點擊 menu key:
D: FirstActivity onPause
D: FirstActivity onSaveInstanceState
D: FirstActivity onStop
3.點擊 App 頁面:
D: FirstActivity onRestart
D: FirstActivity onStart
D: FirstActivity onResume

重點:


1.按下 home key 和 menu key 都會觸發 onSaveInstanceState (在 onPause 之後),但按下 back key 不會觸發 onSaveInstanceState。

2.當 Activity 從後台回到前台都會觸發 onRestart -> onStart -> onResume

 

紀錄2


Activity之間切換的生命週期變化:


2.1修改 FirstActivity,加入啟動 SecondActivity 的功能。

FirstActivity.java
public class FirstActivity extends AppCompatActivity implements OnClickListener {  

private Button mLaunchSecondBtn;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, TAG + " onCreate");
setContentView(R.layout.first_activity);
initUI();
}

private void initUI() {
mLaunchSecondBtn = findViewById(R.id.first_activity_launch);
mLaunchSecondBtn.setOnClickListener(this);
}

@Override
public void onClick(View v) {
int uiID = v.getId();
switch (uiID) {
case R.id.first_activity_launch_second_activity:
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);
finish();
break;
}
}

2.2 新增 SecondActivity 和 FirstActivity 互相切換來觀察生命週期。

SecondActivity.java
public class SecondActivity extends AppCompatActivity implements OnClickListener {  

private static final String TAG = SecondActivity.class.getSimpleName();
private Button mLaunchFirstBtn;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, TAG + " onCreate");
setContentView(R.layout.second_activity);
initUI();
}

@Override
protected void onStart() {
super.onStart();
Log.d(TAG, TAG + " onStart");
}

@Override
protected void onResume() {
super.onResume();
Log.d(TAG, TAG + " onResume");
}

@Override
protected void onPause() {
super.onPause();
Log.d(TAG, TAG + " onPause");
}

@Override
protected void onStop() {
super.onStop();
Log.d(TAG, TAG + " onStop");
}

@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, TAG + " onDestroy");
}

@Override
protected void onRestart() {
super.onRestart();
Log.d(TAG, TAG + " onRestart");
}

@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.d(TAG, TAG + " onSaveInstanceState");
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.d(TAG, TAG + " onRestoreInstanceState");
}

@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.d(TAG, TAG + " onNewIntent");
}

private void initUI() {
mLaunchFirstBtn = findViewById(R.id.second_activity_launch_first_activity);
mLaunchFirstBtn.setOnClickListener(this);
}

@Override
public void onClick(View v) {
int uiID = v.getId();
switch (uiID) {
case R.id.second_activity_launch_first_activity:
Intent intent = new Intent(this,FirstActivity.class);
startActivity(intent);
finish();
break;
}
}
}

A.FirstActivity 啟動 SecondActivity (FirstActivity 不會 finish),再關閉 SecondActivity,再關閉 FirstActivity
1.點擊 App icon 啟動 FirstActivity:
D: FirstActivity onCreate
D: FirstActivity onStart
D: FirstActivity onResume
2.點擊 FirstActivity 的按鈕啟動 SecondActivity。注意 FirstActivity 沒有 finish
D: FirstActivity onPause
D: SecondActivity onCreate
D: SecondActivity onStart
D: SecondActivity onResume
D: FirstActivity onSaveInstanceState
D: FirstActivity onStop
3.點擊 back key 關閉 SecondActivity,讓 FirstActivity 回到前台
D: SecondActivity onPause
D: FirstActivity onRestart
D: FirstActivity onStart
D: FirstActivity onResume
D: SecondActivity onStop
D: SecondActivity onDestroy
4.點擊 back key 關閉 FirstActivity
D: FirstActivity onPause
D: FirstActivity onStop
D: FirstActivity onDestroy

B.FirstActivity 啟動 SecondActivity(FirstActivity 會 finish),再關閉 SecondActivity
1.點擊 App icon 啟動 FristActivity:
D: FirstActivity onCreate
D: FirstActivity onStart
D: FirstActivity onResume
2.點擊 FirstActivity 的按鈕啟動 SecondActivity。注意 FristActivity 會 finish
D: FirstActivity onPause
D: SecondActivity onCreate
D: SecondActivity onStart
D: SecondActivity onResume
D: FirstActivity onStop
D: FirstActivity onDestroy
3.按下 back key 關閉 SecondActivity
D: SecondActivity onPause
D: SecondActivity onStop
D: SecondActivity onDestroy

C.FirstActivity 啟動 SecondActivity(FirstActivity 不會 finish), SecondActivity 再啟動 FirstActivity (SecondActivity不會finish)
1.點擊 App icon 啟動 FristActivity:
D: FirstActivity onCreate
D: FirstActivity onStart
D: FirstActivity onResume
2.點擊 FirstActivity 的按鈕啟動 SecondActivity。注意 FirstActivity 不會 finish
D: FirstActivity onPause
D: SecondActivity onCreate
D: SecondActivity onStart
D: SecondActivity onResume
D: FirstActivity onSaveInstanceState
D: FirstActivity onStop
3.點擊 SecondActivity 的按鈕啟動 FirstActivity。注意 SecondActivity 不會 finish
D: SecondActivity onPause
D: FirstActivity onCreate
D: FirstActivity onStart
D: FirstActivity onResume
D: SecondActivity onSaveInstanceState
D: SecondActivity onStop

D.FirstActivity 啟動 SecondActivity,注意 SecondActivity 使用透明主題(FirstActivity 不會 finish), SecondActivity在啟動 FirstActivity(SecondActivity 不會 finish)
1.點擊 App icon 啟動 FristActivity:
D: FirstActivity onCreate
D: FirstActivity onStart
D: FirstActivity onResume
2.點擊 FirstActivity 的按鈕啟動 SecondActivity(注意 SecondActivity 使用透明主題注意 FirstActivity不會 finish)
D: FirstActivity onPause
D: SecondActivity onCreate
D: SecondActivity onStart
D: SecondActivity onResume
D: FirstActivity onSaveInstanceState
3.點擊 SecondActivity 的按鈕啟動 FirstActivity。注意 SecondActivity 不會 finish
D: SecondActivity onPause
D: FirstActivity onStop
D: FirstActivity onCreate
D: FirstActivity onStart
D: FirstActivity onResume
D: SecondActivity onSaveInstanceState
D: SecondActivity onStop

重點:
1.當第 1 個 Activity 啟動第 2 個 Activity時,會讓第 1 個 Activity先呼叫完 onPause,再進行第 2 個 Activity 的初始化(onCreate -> onStart -> onResume)直到第 2 個 Activity 呼叫完 onResume 之後再進行第 1 個 Activity 的後續動作。

2.當第 1 個 Activity 啟動第 2 個 Activity 時,若第 1 個 Activity 會 finish,則 onSaveInstanceState 不會被呼叫。動作順序如下
(第 1 個 Activity 啟動第 2 個 Activity)
Activity1 onPause
Activity2 onCreate
Activity2 onStart
Activity2 onResume
Activity1 onStop
Activity1 onDestroy
反之,若第 1 個Activity 不會 finish,則 onSaveInstanceState 會在 onStop 之前被呼叫。
(第 1 個 Activity 啟動第 2 個 Activity)
Activity1 onPause
Activity2 onCreate
Activity2 onStart
Activity2 onResume
Activity1 onSaveInstanceState
Activity1 onStop

3.如果要啟動的 Activity(SecondActivity)是透明主題,則啟動者(FirstActivity)啟動 SecondActivity 之後不會呼叫 onStop,如下
(當 FirstActivity 啟動 SecondActivity 之後)
D: FirstActivity onPause
D: SecondActivity onCreate
D: SecondActivity onStart
D: SecondActivity onResume
D: FirstActivity onSaveInstanceState
而當 SecondActivity 啟動 FirstActivity之後才會呼叫 onStop 如下
D: SecondActivity onPause
D: FirstActivity onStop
D: FirstActivity onCreate
D: FirstActivity onStart
D: FirstActivity onResume
D: SecondActivity onSaveInstanceState
D: SecondActivity onStop

紀錄3.


系統配置改變所造成的生命週期變化


當系統配置發生改變,Activity 就會觸發重建過程,最常見的系統配置發生變化為旋轉螢幕。因為這種生命週期變化為系統控制,所以當觸發 onSaveInstanceState 時也會一併呼叫 onRestoreInstanceState 來恢復資料。

A.啟動 FirstActivity 後旋轉螢幕
1.點擊 App icon 啟動 FirstActivity:
D: FirstActivity onCreate
D: FirstActivity onStart
D: FirstActivity onResume
2.旋轉螢幕觸發從直屏到橫屏導致 FirstActivity 重建
D: FirstActivity onPause
D: FirstActivity onSaveInstanceState
D: FirstActivity onStop
D: FirstActivity onDestroy
D: FirstActivity onCreate
D: FirstActivity onStart
D: FirstActivity onRestoreInstanceState
D: FirstActivity onResume
3.再次旋轉螢幕從橫屏到直屏導致 FristActivity 重建
D: FirstActivity onPause
D: FirstActivity onSaveInstanceState
D: FirstActivity onStop
D: FirstActivity onDestroy
D: FirstActivity onCreate
D: FirstActivity onStart
D: FirstActivity onRestoreInstanceState
D: FirstActivity onResume

重點:


1.注意旋轉螢幕之後 onSaveInstanceState 會在 onPause 之後呼叫,而 onRestoreInstanceState 會在 onStart 之後呼叫。

2.若 Activity 要恢復資料可以選擇 onCreate 或 onRestoreInstanceState,差別為於在 onCreate 中需要判斷傳入的參數 Bundle 是否為空,如果是空則不需要恢復資料,而非空才需要進行恢復資料的動作。如下
  @Override  
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
if(savedInstanceState != null){
// restore data
}
}

 

3.若要支援旋轉螢幕,但不重建 Activity,可以在 AndroidManifest.xml 中對該 Activity 設定為
      android:configChanges="orientation|screenSize"

如此,旋轉螢幕之後 Activity 還是會切換直橫屏,但不會重建,資料也不會初始化,在這種情況下若想在旋轉螢幕時收到通知,可在 Activity 覆寫以下方法。(注意該方法只有在 android:configChanges="orientation|screenSize" 被設定時才呼叫)。如下
  @Override  
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.d(TAG, "newConfig.toString():"+newConfig.toString());
}

測試生命週期如下
1.點擊 App icon 啟動 FirstActivity
D: FirstActivity onCreate
D: FirstActivity onStart
D: FirstActivity onResume
2.旋轉螢幕從直屏轉為橫屏
D: newConfig.toString():{0 1.0 ?mcc?mnc zh_TW ldltr sw360dp w640dp h335dp
320dpi nrml long land finger -keyb/v/h -nav/h s.47}
3.旋轉螢幕從橫屏轉為直屏
D: newConfig.toString():{0 1.0 ?mcc?mnc zh_TW ldltr sw360dp w360dp h615dp 320dpi nrml long port finger -keyb/v/h -nav/h s.48}

4.若想保持螢幕為直屏或橫屏,可在 AndroidManifest.xml 的 Activity 加入以下
      android:screenOrientation="portrait"

螢幕便會保持直屏不會旋轉。

5.注意 onRestoreInstanceState 僅用於系統配置變化時(如旋轉螢幕)導致的重建。如果是使用者導致的重建(點擊 back key or home key)則需要在 onCreate 恢復資料。

注意以上 Activity 的生命週期實驗都是以 LaunchMode (啟動模式)為 default,在其它的啟動模式(SingleTop, SingleTask, SingleInstance)則另外需要另外紀錄。

Orignal From: Activity 生命週期紀錄

0 意見:

張貼留言

Twitter Delicious Facebook Digg Stumbleupon Favorites More

 
Design by Free WordPress Themes | Bloggerized by Lasantha - Premium Blogger Themes | Affiliate Network Reviews