Activity的生命週期和啓動模式
activity的基本用法,可以參考這篇文章。
文本是閱讀《Android開發藝術探索》的學習筆記記錄。
Activity的生命週期分析
正常情況下的生命週期
生命週期 | 描述 |
---|---|
onCreate() | 表示activity正在被創建。可以在該方法內做一些初始化工作,比如調用setContentView去加載界面佈局。 |
onRestart() | 表示activity正在被重新啓動。一般是activity從不可見變爲可見時,會調用onRestart。 |
onStart() | 表示activity正在被啓動,即將開始。此時activity已經可見,但是還沒有出現在前臺,無法進行交互。 |
onResume() | 表示activity已經可見了,並且出現在前臺開始活動。 |
onPause() | 表示activity正在被停止。如果此時activity又可見,將會調用onRestart方法。注意在該方法中,可以進行一些輕量級的工作,例如保存數據、停止動畫等。因爲新activity的創建需要當前activity執行完onPause。 |
onStop() | 表示activity不可見,正在被停止。 |
onDestroy() | 表示app即將被銷燬。可以在該方法中做資源的釋放和回收工作。 |
結合上圖,說明一些常見生命週期切換情況。
-
一個activity,第一次啓動過程:onCreate -> onStart -> onResume
-
打開新的activity或者推到桌面時:onPause -> onStop
-
當重新回到原來的activity時:onRestart -> onStart -> onResume
-
當點擊底部back鍵時:onPause -> onStop -> onDestroy
注意
- 區分差別
onStart 和onStop是從activity是否可見角度區分。
onResume和onPause 是從activity是否處於前臺角度區分。
- 先創建activity A再打開一個新activity B,是先執行A的onPause還是B的onResume?
從源碼分析,需要先執行A的onPause方法,再執行B的onResume方法。
異常情況下的生命週期
注意分爲兩種情況,當配置發生改變時以及系統內存不足時。
- 配置發生改變時
如果我們不在AndroidManifest中特別聲明,那麼當手機橫豎屏切換、地區、移動網號等改變時,都會導致activity被銷燬重創。
如果不想因爲它們的改變而重新創建activity可以在AndroidManifest中android:configChanges聲明。可以設置多個屬性,中間用|隔開。
Value | Description |
---|---|
“mcc” | 國際移動用戶識別碼所屬國家代號是改變了----- sim被偵測到了,去更新mcc mcc是移動用戶所屬國家代號 |
“mnc” | 國際移動用戶識別碼的移動網號碼是改變了------ sim被偵測到了,去更新mnc MNC是移動網號碼,最多由兩位數字組成,用於識別移動用戶所歸屬的移動通信網 |
“locale” | 地址改變了-----用戶選擇了一個新的語言會顯示出來 |
“touchscreen” | 觸摸屏是改變了------通常是不會發生的 |
“keyboard” | 鍵盤發生了改變----例如用戶用了外部的鍵盤 |
“keyboardHidden” | 鍵盤的可用性發生了改變 |
“navigation” | 導航發生了變化-----通常也不會發生 |
“screenLayout” | 屏幕的顯示發生了變化------不同的顯示被激活 |
“fontScale” | 字體比例發生了變化----選擇了不同的全局字體 |
“uiMode” | 用戶的模式發生了變化 |
“orientation” | 屏幕方向改變了 |
“screenSize” | 屏幕大小改變了 |
“smallestScreenSize” | 屏幕的物理大小改變了,如:連接到一個外部的屏幕上 |
我們也可以藉助 onSaveInstanceState 方法,它只會在activity異常情況銷燬時調用。進行數據的保留存儲。
當activity被重新創建時,通過 onRestoreInstanceState方法,將數據進行恢復顯示處理。
和activity一樣,每個view的也有onSaveInstanceState和onRestoreInstanceState方法。保存和恢復View層次結構,系統工作流程:activity委託Window去保留數據,Window再委託上面的頂層容器去保存數據。最後頂層容器再一一去通知子元素來保存數據。
例如分析TextView
@Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
// Save state if we are forced to
final boolean freezesText = getFreezesText();
boolean hasSelection = false;
int start = -1;
int end = -1;
if (mText != null) {
start = getSelectionStart();
end = getSelectionEnd();
if (start >= 0 || end >= 0) {
// Or save state if there is a selection
hasSelection = true;
}
}
if (freezesText || hasSelection) {
SavedState ss = new SavedState(superState);
if (freezesText) {
if (mText instanceof Spanned) {
final Spannable sp = new SpannableStringBuilder(mText);
if (mEditor != null) {
removeMisspelledSpans(sp);
sp.removeSpan(mEditor.mSuggestionRangeSpan);
}
ss.text = sp;
} else {
ss.text = mText.toString();
}
}
if (hasSelection) {
// XXX Should also save the current scroll position!
ss.selStart = start;
ss.selEnd = end;
}
if (isFocused() && start >= 0 && end >= 0) {
ss.frozenWithFocus = true;
}
ss.error = getError();
if (mEditor != null) {
ss.editorState = mEditor.saveInstanceState();
}
return ss;
}
return superState;
}
從代碼中可知,TextView保留了自己的文本選擇狀態和文本內容,並在onRestoreInstanceState方法中恢復數據。
- 系統內存不足時
該情況下,數據保存和恢復步驟與情況一一致。列舉activity的優先級。
(1)前臺activity,正在與用戶交互的activity,優先級最高。
(2)可見但是非前臺activity,例如activity彈出窗口未佔滿整個activity界面。
(3)後臺activity,不可見,已經執行了onStop方法。
Activity的啓動模式
有四種啓動模式standard、singleTop、singleTask、singleInstance。在AndroidManifest文件中在< activity >標籤中使用android:launchMode聲明使用模式類型。
溫馨提示,可以使用指令進行棧內消息查看
adb shell dumpsys activity
- standard
標準模式,每啓動一次activity,它就會入棧,並處於棧頂位置。即時棧中已經存在該activity,它也會創建新的實例併入棧。
- singleTop
棧頂複用模式,啓動一個activity時,會判斷棧頂是否已經是該activity。如果是,則不創建新的activity。如果不是,則創建新的activity併入棧。
- singleTask
棧內複用模式,這是一種單實例模式。在啓動一個activity時,會判斷棧中判斷是否已經存在該activity。如果存在,則將該activity之上的其他activity全部出棧,直到該activity處於棧頂結束。如果不存在,則創建新的activity併入棧。
- singleInstance
單實例模式,在啓動一個activity時,會啓動一個新的棧來管理該activity。