簡介
先說下什么是Activity?Activity是Android應用的關鍵組件臭脓,它提供了用戶與應用進行交互的窗口措译,開發(fā)者可以通過這個窗口對界面進行繪制勤晚,展示用戶需要的信息。通常啸臀,一個Activity實現應用中的一個屏幕届宠。例如一個Activity實現“商品詳情”頁面,一個Activity實現“商品列表”頁面乘粒。大多數應用包含多個屏幕豌注,也就是包含多個Activity。通常谓厘,應用中的一個Activity會被指定為主Actvity幌羞,這就是用戶啟動應用時出現的第一個屏幕。一個Activity還可以啟動另外一個Activity竟稳,例如從“商品列表”選擇一個商品跳轉到“商品詳情”属桦。
要想在應用中使用Activity,就必須在AndroidManifest.xml他爸,也叫應用清單文件中使用<Activity></Activity>標簽對Activity進行聲明聂宾,指定需要的屬性。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.androidtest">
<application
android:name=".BaseApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SecondActivity"
android:label="secondActivity">
</activity>
</application>
</manifest>
那么什么是Activity的生命周期呢诊笤?生命周期是指一個Activity從創(chuàng)建到銷毀的過程系谐,Activity提供了一系列的回調方便我們來處理各種生命周期中各種狀態(tài)之間的轉換,下面有一個流程圖讨跟,介紹了Activity狀態(tài)轉換的過程:
流程圖:
從Activity的啟動開始纪他,Activity的創(chuàng)建會執(zhí)行下邊一系列的回調:
onCreate()[創(chuàng)建,不可見]--->onStart()[可見晾匠,不可交互]--->onResume()[可見茶袒,可交互],在resume的狀態(tài)時凉馆,這個Activity就可以與用戶進行交互薪寓,比如常見的點擊、手指上下滑動澜共,捏合等向叉。
Activity創(chuàng)建之后,用戶不會一直停留在這個頁面嗦董,當遇到以下幾種情況時母谎,Activity的狀態(tài)就可以改變,下面對流程圖進行說明:
-
最右邊的流程:
當啟動另外一個Activity或者按home鍵進入后臺的時候京革,Activity從可見變?yōu)椴豢梢姞顟B(tài)奇唤,這個時候會依次執(zhí)行以下回調
onPause()[可見供璧,不可交互]--->onStop()[不可見,不可交互]
我們可以看一下這個時候log打印日志, 日志我省略了無關的信息
D/test: 頁面1 onCreate D/test: 頁面1 onStart D/test: 頁面1 onResume D/test: 跳轉到頁面2 D/test: 頁面1 onPause D/test: -----頁面2 onCreate D/test: -----頁面2 onStart D/test: -----頁面2 onResume D/test: 頁面1 onSaveInstanceState D/test: 頁面1 onStop
-
中間的流程:
當用戶點擊返回按鈕的時候, 我們調用Activity的finish()方法冻记,然后Activity銷毀睡毒,這屬于一種正常的銷毀。如圖中中間的流程冗栗,會依次執(zhí)行以下回調:
onPause()[可見演顾,不可交互]--->onStop()[不可見,不可交互]--->onDestory()[銷毀]
這個時候的log日志如下, 頁面2的流程
D/test: -----頁面2 點擊返回 D/test: -----頁面2 onPause D/test: 頁面1 onRestart D/test: 頁面1 onStart D/test: 頁面1 onResume D/test: -----頁面2 onStop D/test: -----頁面2 onDestroy
-
最左邊的流程:
當系統配置改變(例如屏幕旋轉 )隅居, 或者Activity在后臺钠至,前臺的Activity需要更多資源的時候,系統就必須關閉后臺進程來恢復內存胎源,這個時候系統就有可能銷毀這個Activity棉钧,這種情況就屬于非正常銷毀。如果要模擬非正常銷毀的過程涕蚤,可以打開手機設置里--開發(fā)者選項--不保留活動開關宪卿。這種情況下,Activity被銷毀之后万栅,當用戶再次喚醒這個Activity的時候佑钾,Activity就會被系統重建,下面是系統銷毀到重建的執(zhí)行流程:
onPause--->onStop--->onDestory--->onCreate--->onStart--->onResume()
同樣我們看下這個時候log日志烦粒,我使用旋轉屏幕來模擬了下系統銷毀到創(chuàng)建的過程
D/test: 頁面1 onCreate D/test: 頁面1 onStart D/test: 頁面1 onResume D/test: Application onConfigurationChanged D/test: 頁面1 onPause D/test: 頁面1 onSaveInstanceState D/test: 頁面1 onStop D/test: 頁面1 onDestroy D/test: 頁面1 onCreate D/test: 頁面1 onStart D/test: 頁面1 onResume
生命周期中的各種回調
下面詳細介紹一下Activity的每種回調休溶,大家可以再看一下流程圖,想想都有哪些回調扰她,這些回調有什么區(qū)別兽掰?
-
onCreate(@Nullable Bundle savedInstanceState),創(chuàng)建Activity觸發(fā)徒役,它的下一個回調是onStart()
- 要創(chuàng)建一個Activity孽尽,就必須實現此回調,在Activity首次創(chuàng)建的時候會觸發(fā)該回調, 表明Activity進入“已創(chuàng)建 ”的狀態(tài)廉涕。
- 在Activity整個生命周期中泻云,onCreate只會發(fā)生一次艇拍,我們可以在onCreate方法中執(zhí)行應用的啟動邏輯狐蜕,例如綁定viewmodel,初始化頁面等卸夕。onCreate方法有一個Bundle類型的參數savedInstanceState层释,保存了Activity銷毀前的狀態(tài)。
- 假如Activity被非正常銷毀了快集,比如說配置改變或者內存不足的情況下贡羔,就會被銷毀廉白,在銷毀的時候,系統會調用onSaveInstanceState()回調乖寒, 我們可以在onSaveInstanceState()回調中保存想要保存的數據猴蹂,在頁面重新創(chuàng)建的時候依然還會執(zhí)行onCreate()回調,那么我們就可以從savedInstanceState去獲取我們保存的值楣嘁。這里說明一下磅轻,如果Activity是首次創(chuàng)建,那么savedInstanceState為null逐虚。
//以下示例代碼演示了在onSaveInstanceState如何保存數據聋溜,以及在onCreate中如何獲取保存的數據: //實例中我保存了一個key為isCreate的值 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (savedInstanceState != null) { //在這里獲取數據 Log.d("test", String.valueOf(savedInstanceState.getBoolean("isCreated"))); } } @Override protected void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); //在這里保存數據 outState.putBoolean("isCreated", true); }
Activity中View的狀態(tài)如何保存呢,什么叫View的狀態(tài)叭爱,比如說我們
-
onStart()撮躁,下一個回調是onResume()
該回調是在onCreate之后調用的,表明Activity已進入“已開始”狀態(tài)买雾,頁面此時進入可見狀態(tài)把曼,但是不在前臺,此時還不能交互漓穿。onStart()當頁面被喚醒的時候會被調用祝迂,所以它可以被調用多次
-
onResume(),當Activity進入后臺的時候器净,就會調用onPause()回調
該回調是在onStart之后調用的型雳,表明Activity已進入“已恢復”狀態(tài),用戶回到前臺山害,用戶可以與應用進行交互纠俭。onResume()回調會被執(zhí)行多次,因為每次喚醒之后都會執(zhí)行這個回調浪慌。
Activity創(chuàng)建之后就會一直維持這個狀態(tài)冤荆,直到遇到跳轉到其他頁面,退入后臺等中斷事件的發(fā)生权纤,Activity就退居后臺钓简,不再與用戶進行交互,接下來就會進入onPause()回調
-
onPause()汹想,下一個回調是onStop
調用該回調的時候表示用戶正在離開此Activity, Activity失去了焦點, 進入“已暫停”狀態(tài), 這個時候 Activity依然可見外邓,但是不可與用戶進行交互。如上邊流程圖中的的點擊返回調用finish古掏、home鍵退入后臺或者打開另外一個Activity损话。
onPause()的執(zhí)行非常簡單,而且不一定有足夠的時間來執(zhí)行保存操作,所以丧枪,我們不應該用onPause()來保存數據光涂,執(zhí)行網絡請求,或者數據庫相關操作拧烦,而使用onStop方法來執(zhí)行這些操作
-
onStop()
在onPause之后調用忘闻,表示Activity進入不可見狀態(tài),也就是“已停止”狀態(tài)
-
onDestory(), 表示Activity被銷毀
在Activity銷毀之前恋博,系統會先調用onDestory()回調, 系統調用onDestory的原因下面幾種服赎,可以使用isFinishing()來區(qū)分
- 用戶點擊了返回按鈕,Activity 通過調用finish方法進行返回, 這種情況下的銷毀屬于用戶期望的行為交播,所以Activity是徹底銷毀了重虑,Activity關聯的viewModel也會調用onCleared()方法,銷毀數據秦士, isFinishing = true
- 系統配置變更(例如設備旋轉)或者內存壓力缺厉,系統會暫時銷毀Activity,銷毀之后當用戶喚醒的時候隧土,系統就會創(chuàng)建一個新的Activity提针,這種非正常銷毀,它的viewModel是不會銷毀的曹傀,viewModel會被傳遞給重新創(chuàng)建的Activity辐脖,所以我們可以用viewModel來保存我們視圖相關的數據 ,這種情況下Activity的 isFinishing = false
Activity被銷毀又重建的這種情況下皆愉,有一個問題嗜价,我們該如何保存View的狀態(tài)呢?
首先說一下我們?yōu)槭裁匆4鎂iew的狀態(tài)呢幕庐?
比如有一個非常復雜的表格頁面久锥,需要用戶填各種信息,有非常多的文字輸入控件异剥,多選框瑟由,開關等,但是當用戶花了十幾分鐘終于把頁面填完了冤寿,這個時候不小心旋轉了下屏幕歹苦,上邊說過,如果配置改變了督怜,頁面是會被銷毀重建的殴瘦,那么此時所有填的信息就丟失了,很可怕吧亮蛔。下面演示了這種情況, 當我們沒有EditText設置id的時候痴施,旋轉屏幕之后擎厢,里邊編輯的內容就丟失了:
這個時候我們就需要去保存View的狀態(tài)究流,保證頁面被重新創(chuàng)建的時候View操作的內容依然存在
系統只會保存頁面中我們指定過ID的view狀態(tài)辣吃,系統恢復狀態(tài)時會根據ID找到對應的view去恢復對應的狀態(tài),所以我們在創(chuàng)建view的時候芬探,如果想讓系統保存它的狀態(tài)神得,就一定要設置ID