Android-Activity所應(yīng)該了解的大概就這樣。(上)

本文出自 “阿敏其人” 簡書博客,轉(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 生命周期流程圖

官網(wǎng)翻譯Activity生周期流程圖.png

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

打開,back.gif

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

打開,home.gif
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í)行

任務(wù)列表重選當(dāng)前app.gif

打開自然是: 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代表乙

打開A,A打開B,back.gif

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

鎖屏 解鎖.gif

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的代碼。

橫豎屏切換保存數(shù)據(jù).gif
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)該了解的大概就這樣。(下)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Activity https://developer.android.com/guide/components/a...
    XLsn0w閱讀 723評論 0 4
  • 啟動與銷毀Activity 不同于使用 main() 方法啟動應(yīng)用的其他編程范例,Android 系統(tǒng)會通過調(diào)用對...
    安卓Boy閱讀 1,797評論 3 5
  • 學(xué)習(xí)資料: Android群英傳 Android開發(fā)藝術(shù)探索 Activity是與用戶交互的第一接口,感覺說是四大...
    英勇青銅5閱讀 2,556評論 15 41
  • 4月份圍墻砌起來之后,母親就在那塊預(yù)留地挖出幾壟小小的土堆,在適合下種的清明節(jié)種了一些蔬菜。6月份端午我再回家的時(shí)...
    不一_cc閱讀 437評論 0 0
  • 那時(shí)的我們不以為然,后來的我們無比懷念。 青春大概就是這樣一個矛盾體。 我們一年一年的換教室,一年一年的把我們書本...
    簡簡單單_閱讀 220評論 0 0