本文出自 “阿敏其人” 簡書博客,轉(zhuǎn)載或引用請注明出處。
一、前言
Activity,安卓四大組件之一。
每個 Activity 都會獲得一個用于繪制其用戶界面的窗口。窗口通常會充滿屏幕,但也可小于屏幕并浮動在其他窗口之上。
一個應(yīng)用通常由多個彼此松散聯(lián)系的 Activity 組成。每次新 Activity 啟動時(shí),前一 Activity 便會停止,但系統(tǒng)會在堆棧(“返回棧”)中保留該 Activity。 當(dāng)新 Activity 啟動時(shí),系統(tǒng)會將其推送到返回棧上,并取得用戶焦點(diǎn)。 返回棧遵循“后進(jìn)先出”堆棧機(jī)制,因此,當(dāng)用戶完成當(dāng)前 Activity 并按“返回” **按鈕時(shí),系統(tǒng)會從堆棧中將其彈出(并銷毀),然后恢復(fù)前一 Activity。
當(dāng)一個 Activity 因某個新 Activity 啟動而停止時(shí),系統(tǒng)會通過該 Activity 的生命周期回調(diào)方法通知其這一狀態(tài)變化。Activity 因狀態(tài)變化—系統(tǒng)是創(chuàng)建 Activity、停止 Activity、恢復(fù) Activity 還是銷毀 Activity— 而收到的回調(diào)方法可能有若干種,每一種回調(diào)方法都會為您提供執(zhí)行與該狀態(tài)變化相應(yīng)的特定操作的機(jī)會。
本文按
生命周期、
進(jìn)程的5種優(yōu)先級、
Activity的正常銷毀和異常銷毀、
Activity的啟動模式/4種任務(wù)棧,
Activity的Flag的使用、
圍繞展開。
二、Activity的生命周期
1、Activity生命周期概述
1.1、生命周期6+1方法
簡單來說,6+1的組成的模式(6分為三對)
6個常見的生命周期方法:
- onCreate() 當(dāng)Activity創(chuàng)建時(shí)執(zhí)行
- onStart() 當(dāng)Activity可見時(shí)執(zhí)行(可見了,但是看不到,沒獲得焦點(diǎn))
- onResume() 當(dāng)Activity獲取焦點(diǎn)是執(zhí)行
- onPause() 當(dāng)Activity失去焦點(diǎn)時(shí)執(zhí)行
- onStop() 當(dāng)Activity不可見時(shí)執(zhí)行
- onDestroy() 當(dāng)Activity銷毀時(shí)執(zhí)行
(我的理解是獲取焦點(diǎn)才算真正可見,因?yàn)楂@取了焦點(diǎn)用戶才可以操作,所以可見但是看不到這句話不矛盾)
加1就是加上這個:
- onRestart() 當(dāng)Activity正在重新啟動時(shí)執(zhí)行。
.
.
就上面的6個常見的生命周期:
他們可以說是根據(jù)特征可以分成三組的:
onCreate() 對應(yīng) onDestroy() 創(chuàng)建和銷毀
onStart() 對應(yīng) onStop() 可見和不可見
onResume() 對應(yīng) onPause() 獲取焦點(diǎn)和失去焦點(diǎn)
1.2 生命周期流程圖
1.3 Activity的三種形態(tài)
Activity 基本上以三種狀態(tài)存在:正繼續(xù),已暫停,已停止
正繼續(xù) (Active/Running)
??此 Activity 位于Activity的棧的最頂層,位于屏幕前臺并具有用戶焦點(diǎn),可與用戶進(jìn)行交互。(有時(shí)也將此狀態(tài)稱作“運(yùn)行中”。)
注:關(guān)于棧的知識請看本文的: Activity的啟動模式/4種任務(wù)棧 這一部分
已暫停(Paused)
??Activity已經(jīng)失去焦點(diǎn),無法與用戶進(jìn)行交互。
?? 什么?我們的Activity是可見的?但是沒辦法和用戶交互?弄啥咧?
??是這樣子的,假設(shè)甲Activity是可見的可交互的,但是這時(shí)我們的乙Activity(一個新的非全屏的Activity或者一個透明的Activity)至于棧頂時(shí),即在任務(wù)棧里我們的乙位甲的上方,此刻我們的甲Activity就會處于Paused狀態(tài)了,也就是可見但是沒能進(jìn)行交互。
??
??處于Paused狀態(tài)的甲對象保留在內(nèi)存中,它保留了所有狀態(tài)和成員信息,并與窗口管理器保持連接),但在內(nèi)存極度不足的情況下,可能會被系統(tǒng)終止(進(jìn)程優(yōu)先級的關(guān)系)。
關(guān)于 任務(wù)棧 和 進(jìn)程優(yōu)先級 的知識后面我們也會談及。
已停止(Stoppted)
??該 Activity 被另一個 Activity 完全遮蓋(該 Activity 目前位于“后臺”)。 已停止的 Activity 同樣仍處于 Activity 狀態(tài)(Activity對象保留在內(nèi)存中,它保留了所有狀態(tài)和成員信息,但 沒有 與窗口管理器連接)。
??它對用戶不再可見,在他處需要內(nèi)存時(shí)可能會被系統(tǒng)終止。
2、生命周期方法逐個分析
最普通的正常的情況下我們點(diǎn)開一個新的Activity然后按下返回鍵關(guān)了這個Activity生命周期是這樣子走的:
點(diǎn)開一個新的Activity(還沒開啟過): 先執(zhí)行onCreate,緊接著執(zhí)行onStart,接著這行onResume,然后就停在這個onResume,我們做一些操作嘛。
按下返回鍵:執(zhí)行onPause,接著onStop,然后onDestroy,執(zhí)行了onDestroy了Activity也就銷毀了。
2.1、onCreate()
當(dāng)Activity被創(chuàng)建時(shí)的調(diào)用的方法。只在創(chuàng)建的時(shí)候調(diào)用一次。
可以在這個方法里面做一些初始化的工作,比如setContentView加載布局文件,初始化一些變量的值等。這個是開發(fā)中最常見的方法。
2.2、onStart()
Activity已經(jīng)可見了,但是還沒辦法進(jìn)行交互,可以說我們還看不見。(不要糾結(jié)這句看不見,我們這里本文對于看見的理解是,我必須要能交互我才算看見,不然你說給我看見但是我不能操作屏幕有什么意思。)
2.3 onResume()
Activity已經(jīng)獲取焦點(diǎn)了,Activity處于可見的前臺了。用戶可以進(jìn)行交互了在這個階段。也可以理解為,必須獲取焦點(diǎn)才能進(jìn)行交互。
假設(shè)甲Activity是可見的可交互的,但是這時(shí)我們的乙Activity(一個新的非全屏的Activity或者一個透明的Activity)至于棧頂時(shí),即在任務(wù)棧里我們的乙位甲的上方,此刻我們的甲Activity就會處于Paused狀態(tài)了,也就是可見但是沒能進(jìn)行交互。
2.4 onPause()
Activity已經(jīng)失去焦點(diǎn)了。用戶沒有辦法在這個Activity進(jìn)行操作了。一般來說當(dāng)用戶按下Home鍵或者按下Back鍵就會執(zhí)行這個方法,這個方法執(zhí)行后緊跟著都是執(zhí)行onStop()
如果是按下back鍵:onPause() → onStop() → onDestroy()
如果是按下Home鍵:onPause() → onStop()
onPause方法不能不能進(jìn)行回收工作,簡單說就是這里進(jìn)行回收工作很可能會拖慢影響其他Activty的顯示,后面會涉及到。
回收和清理工作輕一點(diǎn)的科技交給onStop,重一些的交給onDestroy。
2.5 onStop()
Activity不可見了。
在這個方法我們可以進(jìn)行一些比較簡單的回收工作。
2.6 onDestroy()
Activity被銷毀了,這個Activity死掉了,出棧了,拜拜了。
在這里我們可以做一些最終的回收和資源釋放的工作。
2.7 onRestart()
Activity正在重新啟動,也就是從不可見變?yōu)榭梢姷囊粋€過程。
當(dāng)用戶按下Home鍵然后有回到當(dāng)前程序,就會執(zhí)行這個方法,或者當(dāng)用戶從當(dāng)前甲Activity打開一個新的Activity,然后又back鍵返回到甲Activity,又或者用戶按下任務(wù)列表,然后選擇了剛剛打開過的那個程序,那么這個方法也會執(zhí)行。
3、常見的Activity的操作涉及的生命周期
附上代碼先:
MainActivity
public class MainActivity extends Activity {
private static final String TAG="Lifecycle";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "MainActivity onCreate 創(chuàng)建 執(zhí)行");
findViewById(R.id.mTvOpen).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this,SecondActivity.class));
}
});
}
@Override
protected void onStart() {
super.onStart();
Log.d(TAG, "MainActivity onStart 可見 執(zhí)行");
}
@Override
protected void onResume() {
super.onResume();
Log.d(TAG, "MainActivity onResume 獲取焦點(diǎn) 執(zhí)行");
}
@Override
protected void onPause() {
super.onPause();
Log.d(TAG, "MainActivity onPause 失去焦點(diǎn) 執(zhí)行");
}
@Override
protected void onStop() {
super.onStop();
Log.d(TAG, "MainActivity onStop 不可見 執(zhí)行");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "MainActivity onDestroy 銷毀 執(zhí)行");
}
// 以上6個 加 另外一個 onRestart
@Override
protected void onRestart() {
super.onRestart();
Log.d(TAG, "MainActivity onRestart 重新打開Activity");
}
// 重寫兩個方法,數(shù)據(jù)的恢復(fù)和保存
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.d(TAG, "MainActivity onSaveInstanceState 保存數(shù)據(jù)");
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.d(TAG, "MainActivity onRestoreInstanceState 恢復(fù)數(shù)據(jù)");
}
}
.
.
SecondActivity
public class SecondActivity extends Activity{
private static final String TAG="Lifecycle";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "SecondActivity onCreate 創(chuàng)建 執(zhí)行");
}
@Override
protected void onStart() {
super.onStart();
Log.d(TAG, "SecondActivity onStart 可見 執(zhí)行");
}
@Override
protected void onResume() {
super.onResume();
Log.d(TAG, "SecondActivity onResume 獲取焦點(diǎn) 執(zhí)行");
}
@Override
protected void onPause() {
super.onPause();
Log.d(TAG, "SecondActivity onPause 失去焦點(diǎn) 執(zhí)行");
}
@Override
protected void onStop() {
super.onStop();
Log.d(TAG, "SecondActivity onStop 不可見 執(zhí)行");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "SecondActivity onDestroy 銷毀 執(zhí)行");
}
// 以上6個 加 另外一個 onRestart
@Override
protected void onRestart() {
super.onRestart();
Log.d(TAG, "SecondActivity onRestart 重新打開Activity");
}
}
這兩份代碼里面我們在每一個6+1個生命周期的方法都進(jìn)行了對應(yīng)的log打印語句,另外,我們還給MainActivity添加了onSaveInstanceState(數(shù)據(jù)保存)和onRestoreInstanceState(數(shù)據(jù)恢復(fù))的方法的log打印。
3.1、打開一個全新的Activity
(注:3.1-3.6的示例中,先開啟自動屏蔽log中的onSaveInstanceState方法的打印,到了我們說Avtivity的異常銷毀的時(shí)候在回來看,就會知道onSaveInstanceState為什么會出現(xiàn)和出現(xiàn)的作用了。)
onCreate → onStart → onPause
12-02 22:23:42.052 16933-16933/? D/Lifecycle: MainActivity onCreate 創(chuàng)建 執(zhí)行
12-02 22:23:42.052 16933-16933/? D/Lifecycle: MainActivity onStart 可見 執(zhí)行
12-02 22:23:42.052 16933-16933/? D/Lifecycle: MainActivity onResume 獲取焦點(diǎn) 執(zhí)行
3.2 打開一個Activity,接著按下Back鍵
onCreate → onStart → onPause → onPause → onStop → onDestroy
12-02 22:29:50.100 21748-21748/? D/Lifecycle: MainActivity onCreate 創(chuàng)建 執(zhí)行
12-02 22:29:50.100 21748-21748/? D/Lifecycle: MainActivity onStart 可見 執(zhí)行
12-02 22:29:50.100 21748-21748/? D/Lifecycle: MainActivity onResume 獲取焦點(diǎn) 執(zhí)行
12-02 22:29:51.304 21748-21748/com.amqr.activitylifecycle D/Lifecycle: MainActivity onPause 失去焦點(diǎn) 執(zhí)行
12-02 22:29:51.808 21748-21748/com.amqr.activitylifecycle D/Lifecycle: MainActivity onStop 不可見 執(zhí)行
12-02 22:29:51.808 21748-21748/com.amqr.activitylifecycle D/Lifecycle: MainActivity onDestroy 銷毀 執(zhí)行
3.3、打開一個Activity,然后按下Home鍵
打開一個新的Activity:
onCreate → onStart → onResume
按下Home鍵:
onPause → onStop
12-04 21:41:35.407 9001-9001/com.amqr.activitylifecycle D/Lifecycle: MainActivity onCreate 創(chuàng)建 執(zhí)行
12-04 21:41:35.407 9001-9001/com.amqr.activitylifecycle D/Lifecycle: MainActivity onStart 可見 執(zhí)行
12-04 21:41:35.407 9001-9001/com.amqr.activitylifecycle D/Lifecycle: MainActivity onResume 獲取焦點(diǎn) 執(zhí)行
12-04 21:41:36.919 9001-9001/com.amqr.activitylifecycle D/Lifecycle: MainActivity onPause 失去焦點(diǎn) 執(zhí)行
12-04 21:41:37.415 9001-9001/com.amqr.activitylifecycle D/Lifecycle: MainActivity onSaveInstanceState 保存數(shù)據(jù)
12-04 21:41:37.415 9001-9001/com.amqr.activitylifecycle D/Lifecycle: MainActivity onStop 不可見 執(zhí)行
(有一個關(guān)于透明主題不執(zhí)行onStop的說法還沒驗(yàn)證)
3.4、打開程序A,(啟動默認(rèn)的啟動頁MainActivity),按下任務(wù)列表,重新選擇程序A
12-04 21:30:43.979 4670-4670/? D/Lifecycle: MainActivity onCreate 創(chuàng)建 執(zhí)行
12-04 21:30:43.979 4670-4670/? D/Lifecycle: MainActivity onStart 可見 執(zhí)行
12-04 21:30:43.979 4670-4670/? D/Lifecycle: MainActivity onResume 獲取焦點(diǎn) 執(zhí)行
// 按下任務(wù)列表
12-04 21:30:47.319 4670-4670/com.amqr.activitylifecycle D/Lifecycle: MainActivity onPause 失去焦點(diǎn) 執(zhí)行
12-04 21:30:47.979 4670-4670/com.amqr.activitylifecycle D/Lifecycle: MainActivity onSaveInstanceState 保存數(shù)據(jù)
12-04 21:30:47.979 4670-4670/com.amqr.activitylifecycle D/Lifecycle: MainActivity onStop 不可見 執(zhí)行
// 選擇打開app
12-04 21:30:50.811 4670-4670/com.amqr.activitylifecycle D/Lifecycle: MainActivity onRestart 重新打開Activity
12-04 21:30:50.811 4670-4670/com.amqr.activitylifecycle D/Lifecycle: MainActivity onStart 可見 執(zhí)行
12-04 21:30:50.811 4670-4670/com.amqr.activitylifecycle D/Lifecycle: MainActivity onResume 獲取焦點(diǎn) 執(zhí)行
打開自然是: onCreate → onStart → onResume
按下任務(wù)列表:onPause → onStop
選擇這個app:onRestart → onStart → onResume
3.5、打開甲Activity,然后打開乙Activity,接著按下Back鍵 (注意onPause和onStop之間)
打開甲:
甲o(hù)nCreate → 甲o(hù)nStart → 甲o(hù)nResume
接著打開乙:
甲o(hù)nPause
??→ 乙onCreate
??→ 乙onStart
??→ 乙onResume
→ 甲o(hù)nStop
(此時(shí)界面停留在乙)
接著按下Back:
乙onPause
??甲o(hù)nRestart
??甲o(hù)nstart
??甲o(hù)nResume
乙onStop
乙Destroy
(此時(shí)界面停留在甲)
在上面的流程中,我們發(fā)現(xiàn),涉及到其他的Activity的時(shí)候,其他的Activity的生命周期流程是在上一個Activity的onPause和onStop之間完成的。
??記得,不是按部就班等到等到上一個先onPause接著onStop之類在執(zhí)行另外一個Activity的生命周期。
源碼其實(shí)也證明了這一點(diǎn),也就是,舊的Activity必先Pause,接著新的Activity才可以創(chuàng)建。
MainActivity代表甲,SecondActivity代表乙
12-04 21:53:10.751 12020-12020/? D/Lifecycle: MainActivity onCreate 創(chuàng)建 執(zhí)行
12-04 21:53:10.751 12020-12020/? D/Lifecycle: MainActivity onStart 可見 執(zhí)行
12-04 21:53:10.751 12020-12020/? D/Lifecycle: MainActivity onResume 獲取焦點(diǎn) 執(zhí)行
打開B
12-04 21:53:12.919 12020-12020/com.amqr.activitylifecycle D/Lifecycle: MainActivity onPause 失去焦點(diǎn) 執(zhí)行
12-04 21:53:12.923 12020-12020/com.amqr.activitylifecycle D/Lifecycle: SecondActivity onCreate 創(chuàng)建 執(zhí)行
12-04 21:53:12.923 12020-12020/com.amqr.activitylifecycle D/Lifecycle: SecondActivity onStart 可見 執(zhí)行
12-04 21:53:12.923 12020-12020/com.amqr.activitylifecycle D/Lifecycle: SecondActivity onResume 獲取焦點(diǎn) 執(zhí)行
12-04 21:53:13.315 12020-12020/com.amqr.activitylifecycle D/Lifecycle: MainActivity onSaveInstanceState 保存數(shù)據(jù)
12-04 21:53:13.315 12020-12020/com.amqr.activitylifecycle D/Lifecycle: MainActivity onStop 不可見 執(zhí)行
(別看執(zhí)行是MainActivity的onStop,但是現(xiàn)在停留的界面是B)
// Back
12-04 21:53:22.255 12020-12020/com.amqr.activitylifecycle D/Lifecycle: SecondActivity onPause 失去焦點(diǎn) 執(zhí)行
12-04 21:53:22.255 12020-12020/com.amqr.activitylifecycle D/Lifecycle: MainActivity onRestart 重新打開Activity
12-04 21:53:22.255 12020-12020/com.amqr.activitylifecycle D/Lifecycle: MainActivity onStart 可見 執(zhí)行
12-04 21:53:22.255 12020-12020/com.amqr.activitylifecycle D/Lifecycle: MainActivity onResume 獲取焦點(diǎn) 執(zhí)行
12-04 21:53:22.619 12020-12020/com.amqr.activitylifecycle D/Lifecycle: SecondActivity onStop 不可見 執(zhí)行
12-04 21:53:22.619 12020-12020/com.amqr.activitylifecycle D/Lifecycle: SecondActivity onDestroy 銷毀 執(zhí)行
3.6、打開一個新的Activity,鎖屏,解鎖屏幕,
打開新的Activity:
onCreate → onStart → onResume
鎖屏
onPause → onStop
解鎖:
onRestart → onStart → onResume
12-04 22:02:42.191 15855-15855/com.amqr.activitylifecycle D/Lifecycle: MainActivity onCreate 創(chuàng)建 執(zhí)行
12-04 22:02:42.191 15855-15855/com.amqr.activitylifecycle D/Lifecycle: MainActivity onStart 可見 執(zhí)行
12-04 22:02:42.191 15855-15855/com.amqr.activitylifecycle D/Lifecycle: MainActivity onResume 獲取焦點(diǎn) 執(zhí)行
// 鎖屏
12-04 22:02:46.951 15855-15855/com.amqr.activitylifecycle D/Lifecycle: MainActivity onPause 失去焦點(diǎn) 執(zhí)行
12-04 22:02:46.951 15855-15855/com.amqr.activitylifecycle D/Lifecycle: MainActivity onSaveInstanceState 保存數(shù)據(jù)
12-04 22:02:46.951 15855-15855/com.amqr.activitylifecycle D/Lifecycle: MainActivity onStop 不可見 執(zhí)行
// 解鎖
12-04 22:02:49.291 15855-15855/com.amqr.activitylifecycle D/Lifecycle: MainActivity onRestart 重新打開Activity
12-04 22:02:49.291 15855-15855/com.amqr.activitylifecycle D/Lifecycle: MainActivity onStart 可見 執(zhí)行
12-04 22:02:49.315 15855-15855/com.amqr.activitylifecycle D/Lifecycle: MainActivity onResume 獲取焦點(diǎn) 執(zhí)行
.
.
大概的常見的幾種就是像上面這個樣子了。
看了上面打印的log,我們知道 onResume如果要出現(xiàn)一定先出現(xiàn)onstart,對應(yīng)的,onStop要出現(xiàn)那么前面一定先出現(xiàn)onPause。
onstart 接 onResume
onPause 接 onStop
只要清楚了 焦點(diǎn) 和 可見 的區(qū)別,那么上面的流程都是自然而言的,也可以說焦點(diǎn)是個中間人。
谷歌的文檔建議我們不要在onPause做過多的工作,現(xiàn)在通過上面的兩個Activity的切換過程我們也是可以理解的。
舊的Activity必須先Pause,新的才能onCreate,onStart和onResume,既然這樣,為了讓新的界面能夠快速的顯示出來給用戶看,那么onPause肯定不能有太多的重量級操作。
所以,onPause里面不能放耗時(shí)操作,否則影響界面切換速度。
.
.
三、進(jìn)程的優(yōu)先級
上文中我們多次提到當(dāng)內(nèi)存不足時(shí),當(dāng)前Activity被系統(tǒng)gc回收的。那么這回收大概是怎么回收,這肯定是一套復(fù)雜的系統(tǒng),但是這里面涉及到一個進(jìn)程優(yōu)先級的問題。
gc的回收涉及到一個進(jìn)程的優(yōu)先級的問題
1、進(jìn)程的幾個小特點(diǎn)
首先我們知道,一般而言一個App運(yùn)行的就代表一個進(jìn)程在系統(tǒng)執(zhí)行,進(jìn)程大概有以下這么幾個特點(diǎn):
** (1)應(yīng)用程序啟動時(shí)創(chuàng)建了進(jìn)程;**
** (2)應(yīng)用程序退出的時(shí)候,進(jìn)程可能并沒有退出;**
** (3)當(dāng)可用內(nèi)存空間不足,系統(tǒng)會自動清理沒有用到的進(jìn)程;**
2、進(jìn)程的優(yōu)先級分類
進(jìn)程的優(yōu)先級? (針對垃圾回收,誰的優(yōu)先級低就越容易被回收)
安卓的進(jìn)程可以分為這么幾種:
- Foreground process(前臺進(jìn)程)
- Visible process (可視進(jìn)程)
- Service process (服務(wù)進(jìn)程)
- Background process(后臺進(jìn)程)
- Empty process (空進(jìn)程)
2.1. Foreground process(前臺進(jìn)程)
用戶正在操作的應(yīng)用程序所在的進(jìn)程,就是前臺進(jìn)程。即當(dāng)前Activity的onResume方法被執(zhí)行了,可以響應(yīng)點(diǎn)擊事件。
2.2. Visible process (可視進(jìn)程)
應(yīng)用程序的ui界面,用戶還可以看到,但是不能操作了。(比如全透明了,比如一個非全屏的界面在我們的界面的上方)
2.3. Service process (服務(wù)進(jìn)程)
當(dāng)前操作的不是這個程序,但是這個程序有一個后臺的 服務(wù) 還處于運(yùn)行狀態(tài)。
2.4. Background process(后臺進(jìn)程)
應(yīng)用程序沒有服務(wù)處于運(yùn)行狀態(tài),也沒有服務(wù)在運(yùn)行,應(yīng)用程序被最小化了,(activity執(zhí)行了onStop方法,就是界面最小化)
2.5. Empty process (空進(jìn)程)
沒有任何四大組件在運(yùn)行,所有的Activity都關(guān)閉了,任務(wù)棧清空了。(任務(wù)棧的概念我們后面有介紹)
.
.
進(jìn)程的里面優(yōu)先級依次遞減,前臺進(jìn)程優(yōu)先級最高,空進(jìn)程優(yōu)先級最低。
**
??當(dāng)手機(jī)系統(tǒng)內(nèi)容不足,那么手機(jī)會自動回收進(jìn)程,從低級回收起。**
*是不是擔(dān)心如果這樣那如果手機(jī)把我們正在用的進(jìn)程給回收掉怎么辦?如果手機(jī)內(nèi)存滿到要回收前臺進(jìn)程,那么手機(jī)距離卡死關(guān)機(jī)或者自動重啟也就不遠(yuǎn)了
四、Activity的正常銷毀和異常銷毀
1、正常銷毀
一個Activity我們通過按下Home鍵,Back鍵,或者某一個屏幕的空間我們finish掉都是正常銷毀。
2、異常銷毀
正常銷毀自然是最好的,但是Activity也會有異常銷毀的情況,比如下面這兩種情況:
- 1、手機(jī)橫豎屏的切換,Activity被強(qiáng)制撤銷重建,那么就算是異常銷毀了。
- 2、當(dāng)前程序?yàn)楹笈_進(jìn)程時(shí),因?yàn)橄到y(tǒng)內(nèi)存不足給gc回收了。
3、手機(jī)橫豎屏的Activity異常銷毀與SaveInstanceState保存數(shù)據(jù)
我們手機(jī)橫豎屏?xí)?dǎo)致重走生命周期這點(diǎn)我們肯定已經(jīng)是知道的了。
??當(dāng)我們在豎屏的時(shí)候往Edittext里面填寫一些數(shù)據(jù),然后在切換到橫屏,這時(shí)候我們發(fā)現(xiàn)重建完的Activity還保留我們在Edittext的文本。但是在這個過程中我們開發(fā)人員并沒有做什么保存數(shù)據(jù)的操作。那這些為什么數(shù)據(jù)是怎么保存下來的呢?
其實(shí)這就是SaveInstanceState幫我們做的。
說之前我們先來看一下我們熟悉的onCreate的參數(shù)
我們的編碼的時(shí)候復(fù)寫onCreate是經(jīng)常的事,每次參數(shù)里都有一個savedInstanceState,平時(shí)有人也許沒有多大注意它,其實(shí)它干的事情就是在我們的Activity異常銷毀的時(shí)候幫我們保存數(shù)據(jù)用的。
代碼依然采用上面的提供的生命周期示例演示的MainActivity和SecondActivity的代碼。
12-03 02:17:25.388 6883-6883/? D/Lifecycle: MainActivity onCreate 創(chuàng)建 執(zhí)行
12-03 02:17:25.388 6883-6883/? D/Lifecycle: MainActivity onStart 可見 執(zhí)行
12-03 02:17:25.388 6883-6883/? D/Lifecycle: MainActivity onResume 獲取焦點(diǎn) 執(zhí)行
12-03 02:17:28.908 6883-6883/com.amqr.activitylifecycle D/Lifecycle: MainActivity onPause 失去焦點(diǎn) 執(zhí)行
12-03 02:17:28.908 6883-6883/com.amqr.activitylifecycle D/Lifecycle: MainActivity onSaveInstanceState 保存數(shù)據(jù)
12-03 02:17:28.908 6883-6883/com.amqr.activitylifecycle D/Lifecycle: MainActivity onStop 不可見 執(zhí)行
12-03 02:17:28.908 6883-6883/com.amqr.activitylifecycle D/Lifecycle: MainActivity onDestroy 銷毀 執(zhí)行
12-03 02:17:28.932 6883-6883/com.amqr.activitylifecycle D/Lifecycle: MainActivity onCreate 創(chuàng)建 執(zhí)行
12-03 02:17:28.932 6883-6883/com.amqr.activitylifecycle D/Lifecycle: MainActivity onStart 可見 執(zhí)行
12-03 02:17:28.932 6883-6883/com.amqr.activitylifecycle D/Lifecycle: MainActivity onRestoreInstanceState 恢復(fù)數(shù)據(jù)
12-03 02:17:28.932 6883-6883/com.amqr.activitylifecycle D/Lifecycle: MainActivity onResume 獲取焦點(diǎn) 執(zhí)行
從上面的日志打印中我們知道,由于Activity異常銷毀,那么這個時(shí)候的savaInstanceState和onRestoreInstanceState方法都被執(zhí)行了。
就是利用這兩個方法我們才得以實(shí)現(xiàn)數(shù)據(jù)的保存和恢復(fù)的。
當(dāng)我們的程序Activity異常銷毀時(shí),那么savaInstanceState就會調(diào)用,將保存著數(shù)據(jù)的Bundler對象傳遞給onRestoreInstanceState和onCreate()方法。
利用他們兩者一個保存數(shù)據(jù)一個恢復(fù)數(shù)據(jù)的特點(diǎn),其實(shí)我們可以做很多事,只需要在對應(yīng)的復(fù)寫的里面加上對應(yīng)的邏輯就行。比如我們的存數(shù)據(jù)在 安卓的Application,可能因?yàn)槌绦虍惓dN毀而導(dǎo)致數(shù)據(jù)丟失,那么這個時(shí)候應(yīng)可以利用這對方法來進(jìn)行完善了。
相關(guān)了解請參見: 莫往Applicaotion存緩存/app被系統(tǒng)回收之后再打開發(fā)生了什么
savaInstanceState和onRestoreInstanceState方法一般都是配對使用的。
4、savaInstanceState、onRestoreInstanceState的作用
savaInstanceState的作用 : 當(dāng)程序的組件被異常銷毀時(shí),做一定的數(shù)據(jù)保存的工作。
onRestoreInstanceState的作用:恢復(fù)程序被異常的終止時(shí)的數(shù)據(jù)。
5、onRestoreInstanceState方法和onCreate的savedInstanceState參數(shù)
.
.
onCreate的savedInstanceState參數(shù)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "SecondActivity onCreate 創(chuàng)建 執(zhí)行");
}
.
.
onRestoreInstanceState方法
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.d(TAG, "MainActivity onRestoreInstanceState 恢復(fù)數(shù)據(jù)");
}
當(dāng)Activity被異常銷毀時(shí),savaInstanceState會保存的數(shù)據(jù)這個我們已經(jīng)知道了。
保存沒什么可說,恢復(fù)卻出現(xiàn)了不同。
就算我們不復(fù)寫onRestoreInstanceState方法,也可以利用生命周期的onCreate方法參數(shù) savaInstanceState來進(jìn)行數(shù)據(jù)恢復(fù)。
當(dāng)然如果我們復(fù)寫onRestoreInstanceState方法,一樣可進(jìn)行數(shù)據(jù)恢復(fù)。
兩者有什么區(qū)別呢?
- 針對onCreate的參數(shù)Bundle savedInstanceState有可能為空:
??如果之前Activity的savaInstanceState方法沒有執(zhí)行過,那么onCreate的參數(shù)Bundle savedInstanceState有可能為空,這樣就導(dǎo)致了onCreate的參數(shù)Bundle savedInstanceState有可能為空,所以在利用onCreate的參數(shù)Bundle savedInstanceState進(jìn)行數(shù)據(jù)恢復(fù)的時(shí)候需要進(jìn)行參數(shù)的非空判斷,這個參數(shù)不一定是有值的。
- 針對onRestoreInstanceState(推薦):
??如果之前Activity的savaInstanceState方法沒有執(zhí)行過,那么onRestoreInstanceState肯定不會執(zhí)行。也就是說,只要onRestoreInstanceState方法執(zhí)行,那么之前肯定執(zhí)行過savaInstanceState方法。所以,在onRestoreInstanceState方法進(jìn)行恢復(fù)數(shù)據(jù)的時(shí)候,不需要進(jìn)行什么非空判斷,直接用。
所以:推薦在 onRestoreInstanceState 方法進(jìn)行數(shù)據(jù)恢復(fù)。
(Google也是推薦我們這么做的)
6、savaInstanceState和onRestoreInstanceState何時(shí)執(zhí)行
savaInstanceState何時(shí)執(zhí)行:
- 1.當(dāng)用戶按下HOME鍵時(shí)。
??這是顯而易見的,系統(tǒng)不知道你按下HOME后要運(yùn)行多少其他的程序,自然也不知道acitvity A是否會被銷毀所以系統(tǒng)會調(diào)用onSaveInstanceState,讓用戶有機(jī)會保存某些非永久性數(shù)據(jù),以下幾種分析都遵循該原則。(參見 一、3.3,有具體代碼和gif圖片演示 ) - 2.打開任務(wù)列表(長按HOME鍵/長按選項(xiàng)鍵,因機(jī)型而異),按下就執(zhí)行保存數(shù)據(jù)。(參見 四 3)
??因?yàn)槟惆聪氯蝿?wù)列表,你完全有可能選擇其他程序然后玩很久,當(dāng)前這個程序就被冷落好久了,既然被冷落了,就有可能被gc回收,所以保存數(shù)據(jù)很正常。(參見 一、3.4) - 3.從甲Activity 中啟動一個新的activity時(shí)。(參見 一、3.5)
- 4.屏幕橫豎屏切換
- 5、鎖屏(鎖屏?xí)?zhí)行savaInstanceState,解鎖不會執(zhí)行)(參見 一、3.6)
以上說的幾種情況全經(jīng)測試。
具體示例請看 生命周期的示例
onRestoreInstanceState何時(shí)執(zhí)行
Activity被異常銷毀后打開Activity,
橫豎屏切換后打開Activity,
或者說gc回收后打開Activity。
7、題外話,android:configChanges,切屏后不重走生命周期。
可否讓程序切換橫豎屏?xí)r不重走生命周期?可以的
在Activity的manifest里面的配置加上這么一句
android:configChanges="orientation|screenSize"
<activity android:name=".MainActivity"
android:configChanges="orientation|screenSize"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
就可以實(shí)現(xiàn)。為什么呢,我們來分析下:
屏幕方向是一個系統(tǒng)的屬性,鍵盤是否隱藏也是系統(tǒng)的一個屬性,語言也是系統(tǒng)的一個屬性,系統(tǒng)為我們提供了很多的屬性,這些屬性我們都可以利用manifest里面的android:configChanges來執(zhí)行控制是否改變,只要是被指定了的屬性,就會固定下來,無視這個屬性發(fā)生的改變。
安卓部分屬性表
屬性 | 含義 |
---|---|
mcc | 移動國家號碼,由三位數(shù)字組成,每個國家都有自己獨(dú)立的MCC,可以識別手機(jī)用戶所屬國家。 |
mnc | 移動網(wǎng)號,在一個國家或者地區(qū)中,用于區(qū)分手機(jī)用戶的服務(wù)商。 |
locale | 所在地區(qū)發(fā)生變化。 |
touchscreen | 觸摸屏已經(jīng)改變。(少見) |
keyboard | 鍵盤模式發(fā)生變化,例如:用戶接入外部鍵盤輸入。 |
keyboardHidden | 鍵盤的可訪問,用戶調(diào)出了鍵盤 |
navigation | 導(dǎo)航型發(fā)生了變化,比如軌跡球(少見) |
orientation | 最常見,設(shè)備旋轉(zhuǎn),橫向顯示和豎向顯示模式切換。 |
screenSize | 當(dāng)屏幕的尺寸發(fā)生了改變,但是當(dāng)改變屏幕時(shí)尺寸就會認(rèn)為發(fā)生了改變,MiniSdkVersion和 TargetSdkVersion屬性大于等于13的情況下,如果你想阻止程序在運(yùn)行時(shí)重新加載Activity,除了設(shè)置"orientation",你還必須設(shè)置"screenSize"。 |
fontScale | 全局字體大小縮放發(fā)生改變 |
當(dāng)我們想指定多個值,可以用“ | ”把多個屬性連接起來。
其實(shí)這個這個東西用得很少,幾乎都是只用于下面這一點(diǎn):
改變屏幕方向的時(shí)候不要重走生命周期。
(有時(shí)也用于控制鍵盤)
注意的是:
當(dāng)我們的app運(yùn)行的API版本高于13的時(shí)候,需要這么配置:
android:configChanges="orientation|screenSize“
其他的就沒什么啦。
分篇完,其他中篇和下篇鏈接如下
Android-Activity所應(yīng)該了解的大概就這樣。(中)
Android-Activity所應(yīng)該了解的大概就這樣。(下)