Android-Activity所應該了解的大概就這樣扯俱。(上)

本文出自 “阿敏其人” 簡書博客,轉載或引用請注明出處喇澡。

一迅栅、前言

Activity,安卓四大組件之一晴玖。

每個 Activity 都會獲得一個用于繪制其用戶界面的窗口读存。窗口通常會充滿屏幕,但也可小于屏幕并浮動在其他窗口之上呕屎。
一個應用通常由多個彼此松散聯(lián)系的 Activity 組成让簿。每次新 Activity 啟動時,前一 Activity 便會停止秀睛,但系統(tǒng)會在堆棧(“返回椂保”)中保留該 Activity。 當新 Activity 啟動時蹂安,系統(tǒng)會將其推送到返回棧上椭迎,并取得用戶焦點。 返回棧遵循“后進先出”堆棧機制田盈,因此畜号,當用戶完成當前 Activity 并按“返回” **按鈕時,系統(tǒng)會從堆棧中將其彈出(并銷毀)允瞧,然后恢復前一 Activity简软。

當一個 Activity 因某個新 Activity 啟動而停止時蛮拔,系統(tǒng)會通過該 Activity 的生命周期回調方法通知其這一狀態(tài)變化。Activity 因狀態(tài)變化—系統(tǒng)是創(chuàng)建 Activity痹升、停止 Activity建炫、恢復 Activity 還是銷毀 Activity— 而收到的回調方法可能有若干種,每一種回調方法都會為您提供執(zhí)行與該狀態(tài)變化相應的特定操作的機會疼蛾。

本文按
生命周期踱卵、
進程的5種優(yōu)先級、
Activity的正常銷毀和異常銷毀据过、
Activity的啟動模式/4種任務棧惋砂,
Activity的Flag的使用、
圍繞展開绳锅。

二西饵、Activity的生命周期

1、Activity生命周期概述

1.1鳞芙、生命周期6+1方法

簡單來說眷柔,6+1的組成的模式(6分為三對)

6個常見的生命周期方法:

  • onCreate() 當Activity創(chuàng)建時執(zhí)行
  • onStart() 當Activity可見時執(zhí)行(可見了,但是看不到原朝,沒獲得焦點)
  • onResume() 當Activity獲取焦點是執(zhí)行
  • onPause() 當Activity失去焦點時執(zhí)行
  • onStop() 當Activity不可見時執(zhí)行
  • onDestroy() 當Activity銷毀時執(zhí)行
    (我的理解是獲取焦點才算真正可見驯嘱,因為獲取了焦點用戶才可以操作,所以可見但是看不到這句話不矛盾)

加1就是加上這個:

  • onRestart() 當Activity正在重新啟動時執(zhí)行喳坠。
    .
    .
    就上面的6個常見的生命周期:
    他們可以說是根據(jù)特征可以分成三組的:

onCreate() 對應 onDestroy() 創(chuàng)建和銷毀
onStart() 對應 onStop() 可見和不可見
onResume() 對應 onPause() 獲取焦點和失去焦點

1.2 生命周期流程圖

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

1.3 Activity的三種形態(tài)

Activity 基本上以三種狀態(tài)存在:正繼續(xù)鞠评,已暫停,已停止

正繼續(xù) (Active/Running)
??此 Activity 位于Activity的棧的最頂層壕鹉,位于屏幕前臺并具有用戶焦點剃幌,可與用戶進行交互。(有時也將此狀態(tài)稱作“運行中”晾浴。)
注:關于棧的知識請看本文的: Activity的啟動模式/4種任務棧 這一部分
已暫停(Paused)
??Activity已經失去焦點负乡,無法與用戶進行交互。
?? 什么脊凰?我們的Activity是可見的抖棘?但是沒辦法和用戶交互?弄啥咧狸涌?
??是這樣子的切省,假設甲Activity是可見的可交互的,但是這時我們的乙Activity(一個新的非全屏的Activity或者一個透明的Activity)至于棧頂時杈抢,即在任務棧里我們的乙位甲的上方数尿,此刻我們的甲Activity就會處于Paused狀態(tài)了,也就是可見但是沒能進行交互惶楼。
??
??處于Paused狀態(tài)的甲對象保留在內存中,它保留了所有狀態(tài)和成員信息,并與窗口管理器保持連接)歼捐,但在內存極度不足的情況下何陆,可能會被系統(tǒng)終止(進程優(yōu)先級的關系)。

關于 任務棧 和 進程優(yōu)先級 的知識后面我們也會談及豹储。

已停止(Stoppted)
??該 Activity 被另一個 Activity 完全遮蓋(該 Activity 目前位于“后臺”)贷盲。 已停止的 Activity 同樣仍處于 Activity 狀態(tài)(Activity對象保留在內存中,它保留了所有狀態(tài)和成員信息剥扣,但 沒有 與窗口管理器連接)巩剖。
??它對用戶不再可見,在他處需要內存時可能會被系統(tǒng)終止钠怯。

2佳魔、生命周期方法逐個分析

最普通的正常的情況下我們點開一個新的Activity然后按下返回鍵關了這個Activity生命周期是這樣子走的:
點開一個新的Activity(還沒開啟過): 先執(zhí)行onCreate,緊接著執(zhí)行onStart晦炊,接著這行onResume鞠鲜,然后就停在這個onResume,我們做一些操作嘛断国。
按下返回鍵:執(zhí)行onPause贤姆,接著onStop,然后onDestroy稳衬,執(zhí)行了onDestroy了Activity也就銷毀了霞捡。

2.1、onCreate()

當Activity被創(chuàng)建時的調用的方法薄疚。只在創(chuàng)建的時候調用一次姥闭。
可以在這個方法里面做一些初始化的工作,比如setContentView加載布局文件馏慨,初始化一些變量的值等哥蔚。這個是開發(fā)中最常見的方法。

2.2莱坎、onStart()

Activity已經可見了衣式,但是還沒辦法進行交互,可以說我們還看不見檐什。(不要糾結這句看不見碴卧,我們這里本文對于看見的理解是,我必須要能交互我才算看見乃正,不然你說給我看見但是我不能操作屏幕有什么意思住册。)

2.3 onResume()

Activity已經獲取焦點了,Activity處于可見的前臺了瓮具。用戶可以進行交互了在這個階段荧飞。也可以理解為凡人,必須獲取焦點才能進行交互。

假設甲Activity是可見的可交互的叹阔,但是這時我們的乙Activity(一個新的非全屏的Activity或者一個透明的Activity)至于棧頂時挠轴,即在任務棧里我們的乙位甲的上方,此刻我們的甲Activity就會處于Paused狀態(tài)了耳幢,也就是可見但是沒能進行交互岸晦。

2.4 onPause()

Activity已經失去焦點了。用戶沒有辦法在這個Activity進行操作了睛藻。一般來說當用戶按下Home鍵或者按下Back鍵就會執(zhí)行這個方法启上,這個方法執(zhí)行后緊跟著都是執(zhí)行onStop()
如果是按下back鍵:onPause() → onStop() → onDestroy()
如果是按下Home鍵:onPause() → onStop()

onPause方法不能不能進行回收工作,簡單說就是這里進行回收工作很可能會拖慢影響其他Activty的顯示店印,后面會涉及到冈在。
回收和清理工作輕一點的科技交給onStop,重一些的交給onDestroy吱窝。

2.5 onStop()

Activity不可見了讥邻。
在這個方法我們可以進行一些比較簡單的回收工作。

2.6 onDestroy()

Activity被銷毀了院峡,這個Activity死掉了兴使,出棧了,拜拜了照激。
在這里我們可以做一些最終的回收和資源釋放的工作发魄。

2.7 onRestart()

Activity正在重新啟動,也就是從不可見變?yōu)榭梢姷囊粋€過程俩垃。
當用戶按下Home鍵然后有回到當前程序励幼,就會執(zhí)行這個方法,或者當用戶從當前甲Activity打開一個新的Activity口柳,然后又back鍵返回到甲Activity苹粟,又或者用戶按下任務列表,然后選擇了剛剛打開過的那個程序跃闹,那么這個方法也會執(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  獲取焦點 執(zhí)行");

    }


    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "MainActivity onPause  失去焦點 執(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ù)的恢復和保存
    @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  恢復數(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  獲取焦點 執(zhí)行");

    }


    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "SecondActivity onPause  失去焦點 執(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個生命周期的方法都進行了對應的log打印語句苛秕,另外,我們還給MainActivity添加了onSaveInstanceState(數(shù)據(jù)保存)和onRestoreInstanceState(數(shù)據(jù)恢復)的方法的log打印找默。

3.1艇劫、打開一個全新的Activity

(注:3.1-3.6的示例中,先開啟自動屏蔽log中的onSaveInstanceState方法的打印惩激,到了我們說Avtivity的異常銷毀的時候在回來看店煞,就會知道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  獲取焦點 執(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  獲取焦點 執(zhí)行
12-02 22:29:51.304 21748-21748/com.amqr.activitylifecycle D/Lifecycle: MainActivity onPause  失去焦點 執(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  獲取焦點 執(zhí)行

12-04 21:41:36.919 9001-9001/com.amqr.activitylifecycle D/Lifecycle: MainActivity onPause  失去焦點 執(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í)行

(有一個關于透明主題不執(zhí)行onStop的說法還沒驗證)

3.4衩椒、打開程序A,(啟動默認的啟動頁MainActivity)哮兰,按下任務列表毛萌,重新選擇程序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  獲取焦點 執(zhí)行
// 按下任務列表
12-04 21:30:47.319 4670-4670/com.amqr.activitylifecycle D/Lifecycle: MainActivity onPause  失去焦點 執(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  獲取焦點 執(zhí)行

任務列表重選當前app.gif

打開自然是: onCreate → onStart → onResume
按下任務列表:onPause → onStop
選擇這個app:onRestart → onStart → onResume

3.5、打開甲Activity喝滞,然后打開乙Activity阁将,接著按下Back鍵 (注意onPause和onStop之間)

打開甲:
甲onCreate → 甲onStart → 甲onResume

接著打開乙:
甲onPause
??→ 乙onCreate
??→ 乙onStart
??→ 乙onResume
→ 甲onStop
(此時界面停留在乙)

接著按下Back:
乙onPause
??甲onRestart
??甲onstart
??甲onResume
乙onStop
乙Destroy
(此時界面停留在甲)

在上面的流程中,我們發(fā)現(xiàn)右遭,涉及到其他的Activity的時候做盅,其他的Activity的生命周期流程是在上一個Activity的onPause和onStop之間完成的。
??記得窘哈,不是按部就班等到等到上一個先onPause接著onStop之類在執(zhí)行另外一個Activity的生命周期吹榴。

源碼其實也證明了這一點,也就是滚婉,舊的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  獲取焦點 執(zhí)行
打開B
12-04 21:53:12.919 12020-12020/com.amqr.activitylifecycle D/Lifecycle: MainActivity onPause  失去焦點 執(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  獲取焦點 執(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  失去焦點 執(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  獲取焦點 執(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  獲取焦點 執(zhí)行

// 鎖屏
12-04 22:02:46.951 15855-15855/com.amqr.activitylifecycle D/Lifecycle: MainActivity onPause  失去焦點 執(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  獲取焦點 執(zhí)行

.
.
大概的常見的幾種就是像上面這個樣子了。
看了上面打印的log只估,我們知道 onResume如果要出現(xiàn)一定先出現(xiàn)onstart志群,對應的,onStop要出現(xiàn)那么前面一定先出現(xiàn)onPause蛔钙。

onstart 接 onResume
onPause 接 onStop

只要清楚了 焦點 和 可見 的區(qū)別锌云,那么上面的流程都是自然而言的,也可以說焦點是個中間人吁脱。

谷歌的文檔建議我們不要在onPause做過多的工作桑涎,現(xiàn)在通過上面的兩個Activity的切換過程我們也是可以理解的彬向。
舊的Activity必須先Pause,新的才能onCreate攻冷,onStart和onResume娃胆,既然這樣,為了讓新的界面能夠快速的顯示出來給用戶看等曼,那么onPause肯定不能有太多的重量級操作里烦。
所以,onPause里面不能放耗時操作禁谦,否則影響界面切換速度胁黑。

.
.

三、進程的優(yōu)先級

上文中我們多次提到當內存不足時州泊,當前Activity被系統(tǒng)gc回收的丧蘸。那么這回收大概是怎么回收,這肯定是一套復雜的系統(tǒng)遥皂,但是這里面涉及到一個進程優(yōu)先級的問題力喷。

gc的回收涉及到一個進程的優(yōu)先級的問題

1、進程的幾個小特點

首先我們知道演训,一般而言一個App運行的就代表一個進程在系統(tǒng)執(zhí)行弟孟,進程大概有以下這么幾個特點:

** (1)應用程序啟動時創(chuàng)建了進程;**
** (2)應用程序退出的時候仇祭,進程可能并沒有退出披蕉;**
** (3)當可用內存空間不足,系統(tǒng)會自動清理沒有用到的進程乌奇;**

2没讲、進程的優(yōu)先級分類

進程的優(yōu)先級? (針對垃圾回收,誰的優(yōu)先級低就越容易被回收)

安卓的進程可以分為這么幾種:

  • Foreground process(前臺進程)
  • Visible process (可視進程)
  • Service process (服務進程)
  • Background process(后臺進程)
  • Empty process (空進程)

2.1. Foreground process(前臺進程)

用戶正在操作的應用程序所在的進程礁苗,就是前臺進程爬凑。即當前Activity的onResume方法被執(zhí)行了,可以響應點擊事件试伙。

2.2. Visible process (可視進程)

應用程序的ui界面嘁信,用戶還可以看到,但是不能操作了疏叨。(比如全透明了潘靖,比如一個非全屏的界面在我們的界面的上方)

2.3. Service process (服務進程)

當前操作的不是這個程序,但是這個程序有一個后臺的 服務 還處于運行狀態(tài)蚤蔓。

2.4. Background process(后臺進程)

應用程序沒有服務處于運行狀態(tài)卦溢,也沒有服務在運行,應用程序被最小化了,(activity執(zhí)行了onStop方法单寂,就是界面最小化)

2.5. Empty process (空進程)

沒有任何四大組件在運行贬芥,所有的Activity都關閉了,任務棧清空了宣决。(任務棧的概念我們后面有介紹)

.
.

進程的里面優(yōu)先級依次遞減蘸劈,前臺進程優(yōu)先級最高,空進程優(yōu)先級最低尊沸。
**
??
當手機系統(tǒng)內容不足威沫,那么手機會自動回收進程,從低級回收起椒丧。**

*是不是擔心如果這樣那如果手機把我們正在用的進程給回收掉怎么辦壹甥?如果手機內存滿到要回收前臺進程救巷,那么手機距離卡死關機或者自動重啟也就不遠了

四壶熏、Activity的正常銷毀和異常銷毀

1、正常銷毀

一個Activity我們通過按下Home鍵浦译,Back鍵棒假,或者某一個屏幕的空間我們finish掉都是正常銷毀。

2精盅、異常銷毀

正常銷毀自然是最好的帽哑,但是Activity也會有異常銷毀的情況,比如下面這兩種情況:

  • 1叹俏、手機橫豎屏的切換妻枕,Activity被強制撤銷重建,那么就算是異常銷毀了粘驰。
  • 2屡谐、當前程序為后臺進程時,因為系統(tǒng)內存不足給gc回收了蝌数。

3愕掏、手機橫豎屏的Activity異常銷毀與SaveInstanceState保存數(shù)據(jù)

我們手機橫豎屏會導致重走生命周期這點我們肯定已經是知道的了。
??當我們在豎屏的時候往Edittext里面填寫一些數(shù)據(jù)顶伞,然后在切換到橫屏饵撑,這時候我們發(fā)現(xiàn)重建完的Activity還保留我們在Edittext的文本。但是在這個過程中我們開發(fā)人員并沒有做什么保存數(shù)據(jù)的操作唆貌。那這些為什么數(shù)據(jù)是怎么保存下來的呢滑潘?

其實這就是SaveInstanceState幫我們做的。

說之前我們先來看一下我們熟悉的onCreate的參數(shù)
我們的編碼的時候復寫onCreate是經常的事锨咙,每次參數(shù)里都有一個savedInstanceState语卤,平時有人也許沒有多大注意它,其實它干的事情就是在我們的Activity異常銷毀的時候幫我們保存數(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  獲取焦點 執(zhí)行

12-03 02:17:28.908 6883-6883/com.amqr.activitylifecycle D/Lifecycle: MainActivity onPause  失去焦點 執(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  恢復數(shù)據(jù)
12-03 02:17:28.932 6883-6883/com.amqr.activitylifecycle D/Lifecycle: MainActivity onResume  獲取焦點 執(zhí)行

從上面的日志打印中我們知道羊壹,由于Activity異常銷毀,那么這個時候的savaInstanceState和onRestoreInstanceState方法都被執(zhí)行了齐婴。

就是利用這兩個方法我們才得以實現(xiàn)數(shù)據(jù)的保存和恢復的油猫。

當我們的程序Activity異常銷毀時,那么savaInstanceState就會調用柠偶,將保存著數(shù)據(jù)的Bundler對象傳遞給onRestoreInstanceState和onCreate()方法情妖。

利用他們兩者一個保存數(shù)據(jù)一個恢復數(shù)據(jù)的特點,其實我們可以做很多事诱担,只需要在對應的復寫的里面加上對應的邏輯就行毡证。比如我們的存數(shù)據(jù)在 安卓的Application,可能因為程序異常銷毀而導致數(shù)據(jù)丟失蔫仙,那么這個時候應可以利用這對方法來進行完善了料睛。
相關了解請參見: 莫往Applicaotion存緩存/app被系統(tǒng)回收之后再打開發(fā)生了什么

savaInstanceState和onRestoreInstanceState方法一般都是配對使用的。

4摇邦、savaInstanceState恤煞、onRestoreInstanceState的作用

savaInstanceState的作用 : 當程序的組件被異常銷毀時,做一定的數(shù)據(jù)保存的工作施籍。
onRestoreInstanceState的作用:恢復程序被異常的終止時的數(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  恢復數(shù)據(jù)");
    }

當Activity被異常銷毀時丑慎,savaInstanceState會保存的數(shù)據(jù)這個我們已經知道了喜喂。

保存沒什么可說,恢復卻出現(xiàn)了不同竿裂。
就算我們不復寫onRestoreInstanceState方法玉吁,也可以利用生命周期的onCreate方法參數(shù) savaInstanceState來進行數(shù)據(jù)恢復。
當然如果我們復寫onRestoreInstanceState方法,一樣可進行數(shù)據(jù)恢復铛绰。

兩者有什么區(qū)別呢诈茧?

  • 針對onCreate的參數(shù)Bundle savedInstanceState有可能為空:
    ??如果之前Activity的savaInstanceState方法沒有執(zhí)行過,那么onCreate的參數(shù)Bundle savedInstanceState有可能為空捂掰,這樣就導致了onCreate的參數(shù)Bundle savedInstanceState有可能為空敢会,所以在利用onCreate的參數(shù)Bundle savedInstanceState進行數(shù)據(jù)恢復的時候需要進行參數(shù)的非空判斷,這個參數(shù)不一定是有值的这嚣。
  • 針對onRestoreInstanceState(推薦):
    ??如果之前Activity的savaInstanceState方法沒有執(zhí)行過鸥昏,那么onRestoreInstanceState肯定不會執(zhí)行。也就是說姐帚,只要onRestoreInstanceState方法執(zhí)行吏垮,那么之前肯定執(zhí)行過savaInstanceState方法。所以,在onRestoreInstanceState方法進行恢復數(shù)據(jù)的時候膳汪,不需要進行什么非空判斷,直接用唯蝶。

所以:推薦在 onRestoreInstanceState 方法進行數(shù)據(jù)恢復。
(Google也是推薦我們這么做的)

6遗嗽、savaInstanceState和onRestoreInstanceState何時執(zhí)行

savaInstanceState何時執(zhí)行:

  • 1.當用戶按下HOME鍵時粘我。
    ??這是顯而易見的,系統(tǒng)不知道你按下HOME后要運行多少其他的程序痹换,自然也不知道acitvity A是否會被銷毀所以系統(tǒng)會調用onSaveInstanceState,讓用戶有機會保存某些非永久性數(shù)據(jù)征字,以下幾種分析都遵循該原則。(參見 一娇豫、3.3匙姜,有具體代碼和gif圖片演示 )
  • 2.打開任務列表(長按HOME鍵/長按選項鍵,因機型而異)冯痢,按下就執(zhí)行保存數(shù)據(jù)氮昧。(參見 四 3)
    ??因為你按下任務列表,你完全有可能選擇其他程序然后玩很久系羞,當前這個程序就被冷落好久了郭计,既然被冷落了,就有可能被gc回收椒振,所以保存數(shù)據(jù)很正常。(參見 一梧乘、3.4)
  • 3.從甲Activity 中啟動一個新的activity時澎迎。(參見 一、3.5)
  • 4.屏幕橫豎屏切換
  • 5选调、鎖屏(鎖屏會執(zhí)行savaInstanceState夹供,解鎖不會執(zhí)行)(參見 一、3.6)
    以上說的幾種情況全經測試仁堪。

具體示例請看 生命周期的示例

onRestoreInstanceState何時執(zhí)行

Activity被異常銷毀后打開Activity哮洽,
橫豎屏切換后打開Activity,
或者說gc回收后打開Activity弦聂。

7鸟辅、題外話,android:configChanges莺葫,切屏后不重走生命周期匪凉。

可否讓程序切換橫豎屏時不重走生命周期?可以的
在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>

就可以實現(xiàn)捺檬。為什么呢再层,我們來分析下:

屏幕方向是一個系統(tǒng)的屬性,鍵盤是否隱藏也是系統(tǒng)的一個屬性,語言也是系統(tǒng)的一個屬性聂受,系統(tǒng)為我們提供了很多的屬性蒿秦,這些屬性我們都可以利用manifest里面的android:configChanges來執(zhí)行控制是否改變,只要是被指定了的屬性蛋济,就會固定下來渤早,無視這個屬性發(fā)生的改變。

安卓部分屬性表

屬性 含義
mcc 移動國家號碼瘫俊,由三位數(shù)字組成鹊杖,每個國家都有自己獨立的MCC,可以識別手機用戶所屬國家扛芽。
mnc 移動網(wǎng)號骂蓖,在一個國家或者地區(qū)中,用于區(qū)分手機用戶的服務商川尖。
locale 所在地區(qū)發(fā)生變化登下。
touchscreen 觸摸屏已經改變。(少見)
keyboard 鍵盤模式發(fā)生變化叮喳,例如:用戶接入外部鍵盤輸入被芳。
keyboardHidden 鍵盤的可訪問,用戶調出了鍵盤
navigation 導航型發(fā)生了變化馍悟,比如軌跡球(少見)
orientation 最常見畔濒,設備旋轉,橫向顯示和豎向顯示模式切換锣咒。
screenSize 當屏幕的尺寸發(fā)生了改變侵状,但是當改變屏幕時尺寸就會認為發(fā)生了改變,MiniSdkVersion和 TargetSdkVersion屬性大于等于13的情況下毅整,如果你想阻止程序在運行時重新加載Activity趣兄,除了設置"orientation",你還必須設置"screenSize"悼嫉。
fontScale 全局字體大小縮放發(fā)生改變

當我們想指定多個值艇潭,可以用“ | ”把多個屬性連接起來。

其實這個這個東西用得很少戏蔑,幾乎都是只用于下面這一點:
改變屏幕方向的時候不要重走生命周期蹋凝。
(有時也用于控制鍵盤)

注意的是:
當我們的app運行的API版本高于13的時候,需要這么配置:
android:configChanges="orientation|screenSize“

其他的就沒什么啦辛臊。

分篇完仙粱,其他中篇和下篇鏈接如下

Android-Activity所應該了解的大概就這樣。(中)
Android-Activity所應該了解的大概就這樣彻舰。(下)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末伐割,一起剝皮案震驚了整個濱河市候味,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌隔心,老刑警劉巖白群,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異硬霍,居然都是意外死亡帜慢,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門唯卖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來粱玲,“玉大人,你說我怎么就攤上這事拜轨〕榧酰” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵橄碾,是天一觀的道長卵沉。 經常有香客問我,道長法牲,這世上最難降的妖魔是什么史汗? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮拒垃,結果婚禮上停撞,老公的妹妹穿的比我還像新娘。我一直安慰自己恶复,他們只是感情好怜森,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著谤牡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪姥宝。 梳的紋絲不亂的頭發(fā)上翅萤,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音腊满,去河邊找鬼套么。 笑死,一個胖子當著我的面吹牛碳蛋,可吹牛的內容都是我干的胚泌。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼肃弟,長吁一口氣:“原來是場噩夢啊……” “哼玷室!你這毒婦竟也來了零蓉?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤穷缤,失蹤者是張志新(化名)和其女友劉穎敌蜂,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體津肛,經...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡章喉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了身坐。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片秸脱。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖部蛇,靈堂內的尸體忽然破棺而出摊唇,到底是詐尸還是另有隱情,我是刑警寧澤搪花,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布遏片,位于F島的核電站,受9級特大地震影響撮竿,放射性物質發(fā)生泄漏吮便。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一幢踏、第九天 我趴在偏房一處隱蔽的房頂上張望髓需。 院中可真熱鬧,春花似錦房蝉、人聲如沸僚匆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽咧擂。三九已至,卻和暖如春檀蹋,著一層夾襖步出監(jiān)牢的瞬間松申,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工俯逾, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留贸桶,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓桌肴,卻偏偏與公主長得像皇筛,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子坠七,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內容

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