Android系統編程入門系列之加載界面Activity

上回說到應用初始化加載及其生命週期,在Android系統調用Applicaiton.onCreate()以後,繼續建立並加載清單文件中註冊的首個界面即主Activity,也可稱之爲入口界面。主Activity的肯定規則在Android系統編程入門系列之清單文件有介紹,本文主要介紹Android系統建立Activity以後的生命週期流程。
在清單文件中所註冊的界面均爲自定義Activity,其父類往上追溯,必須繼承自android.content.Activityhtml

生命週期

Activity做爲四大組件之首,主要負責與系統使用者的可視化交互響應。只有深入掌握Activity的生命週期及相關概念,才能在開發設計時遊刃有餘。注意,這裏的生命週期介紹,與官方生命週期定義有所區別,本文中的範圍更加寬泛。android

Android組件的生命週期,均是由Android系統主線程調用,若是在調用的生命週期方法內出現耗時操做,將會致使後續的生命週期方法沒法被及時調用,反應到交互界面上就是應用程序卡頓甚至操做無響應。爲了防止這種狀況的發生,Android系統定義當應用程序超時無響應時間超過必定時長(界面Activity默認5秒),會觸發應用無響應錯誤ANR,同時界面彈出提示對話框,以供用戶選擇退出中止響應或繼續等待。因此在生命週期方法內不容許耗時操做。編程

(調用構造方法)啓動實例化

界面Activity的啓動須要經過android.content.Intent意圖來操做,意圖的建立分顯示意圖和隱示意圖兩種類型。顧名思義,顯示意圖要指定Activity的具體包名和類名,而隱示意圖只須要指定Activity在清單文件中註冊時所嵌入的actioncategory標籤信息。建立的意圖做爲參數才能啓動界面Activity。顯示意圖經常使用於當前應用內的界面Activity之間啓動,而隱示意圖多用於不一樣應用間的界面啓動。數據結構

回想下,在Android系統編程入門系列之清單文件文章中說到,主Activity的註冊時,必須在其標籤內部嵌入<intent-filter></intent-filter>標籤,並在該標籤內固定且惟一<action><category>標籤的內容。這種寫法的緣由,就在於Android系統是建立的隱示意圖啓動應用內的主Activity。觸類旁通,留個問題思考下,若是一個應用的清單文件中有多個上述主Activity的固定<intent-filter></intent-filter>標籤內容,那Android系統在啓動這個應用後會怎麼調用這些Activity呢?(答案將在相應視頻教程中揭曉)app

在Android系統經過清單文件找到意圖指定的界面Activity以後,會實例化該界面Activity對象,並將其放入當前應用程序的指定任務棧中。任務棧,正如其名,是採用先進後出的模式管理當前應用程序啓動的全部界面Activity對象的數據結構。ide

當界面Activity啓動時放入任務棧中,退出界面Activity時則從任務棧中取出其對象並銷燬。然而若是一個應用程序只對應一個任務棧,在有些頻繁啓動退出單個界面的場景中,就會頻繁建立銷燬該界面實例,浪費了不少cpu耗時。爲了優化界面的實例化過程,Android系統容許一個應用程序使用多個任務棧。這也就引出了兩個問題,一是如何從多個任務棧中指定具體一個做爲界面啓動管理的任務棧?二是界面在啓動時放入不一樣任務棧的規則是什麼?優化

對於第一個問題,在清單文件中靜態註冊界面Activity時,能夠在<activity></activity>標籤中對屬性名taskAffinity賦值,該屬性值默認爲當前應用包名,從而指定當前界面Activity所屬的任務棧。而<application></application>標籤中也可使用該屬性,表示當前應用程序內的全部界面啓動時都使用該屬性值對應的任務棧管理。同時在界面Activity中,可使用getTaskId()來獲取當前界面Activity所屬任務棧對應的id值。ui

對於第二個問題,能夠根據界面Activity啓動模式來肯定放入任務棧的規則。啓動模式能夠在清單文件中靜態註冊<activity></activity>標籤時,指定其屬性launchMode賦值;也能夠在建立意圖Intent操做以後,經過調用其setFlags(int flags)方法動態設置。若是動態設置方式會優先覆蓋靜態設置方式,若是不設置啓動模式,則使用默認模式啓動。啓動模式主要有四種,其具體方式和對應的屬性值可參考下表。google

啓動模式 靜態設置 動態設置 功能含義
標準模式(默認模式) standard - 啓動時會在內存空間中實例化對象,並將該對象放入指定任務棧中
棧頂單例模式 singleTop Intent.FLAG_ACTIVITY_SINGLE_TOP 啓動時先檢查指定任務棧頂部界面對象,
若是與該界面信息一致,則使用任務棧頂層的對象;
不然實例化對象並放入指定任務棧頂部
棧內單例模式 singleTask Intent.FLAG_ACTIVITY_CLEAR_TOP 啓動時檢查指定任務棧內的全部界面對象,
若是存在與該界面信息一致的對象,則將其頂部界面對象移出任務棧並銷燬,最終保留一致對象在任務棧頂部;
不然實例化對象並放入指定任務棧頂部
全局單例模式 singleInstance Intent.FLAG_ACTIVITY_NEW_TASK 啓動時檢查當前應用程序使用的全部任務棧內的全部界面對象,
若是存在與該界面信息一致的對象,則將其所在任務棧頂部的界面對象移出任務棧並銷燬,最終保留一致對象在任務棧頂部;
不然實例化對象並放入指定任務棧頂部

在界面`Activity`啓動實例化階段,只是建立實例,並未加載Android系統相關環境,故該階段通常不須要重寫構造方法。

(調用attachBaseContext(Context base))加載運行環境

Application同樣,Activity也繼承自android.content.ContentWrapper,使用時綁定上下文環境,尤其注意的是,在AndroidSDK定義的全部android.content.ContentWrapper子類中,只有android.content.Activity類中重寫了attachBaseContext(Context base)方法。故界面Activity實例化以後,系統會最終調用android.content.Activity.attachBaseContext(Context base)方法,在該方法中以完成將當前界面與上下文環境綁定的任務。線程

一樣的,在界面Activity加載運行環境階段,也不推薦重寫該方法,界面內全部的操做都應在該方法以後完成。

(調用onCreate())界面建立

在界面加載運行環境以後,Android系統對界面的建立工做就完成了。以後系統回調onCreate()方法,官方稱之爲已建立狀態。此時當前Activity還處在後臺未展現給用戶,所以能夠重寫該方法,以完成界面內相關變量的初始化操做。

(調用onStart())界面展現

在界面建立以後,或界面從新展現以後,系統會回調onStart()方法,將當前Activity繪製給用戶可見,官方稱之爲已開始狀態。若是重寫該方法,能夠完成展現給用戶的界面初始化操做。

(調用onResume())界面運行

當界面展現以後,系統會回調onResume()方法,使得界面能夠與用戶進行交互,官方稱之爲已恢復狀態。此時系統開始響應該界面內的用戶交互,這也代表當前界面Activity已經處於運行了。

系統調用該生命週期方法後會一直處於界面運行中,直到用戶的一些操做改變該界面的狀態。這些用戶操做包括但不限於:

  1. 在該界面Activity啓動另外一個界面Activity
  2. 點擊back返回按鍵,退出該界面Activity,返回上一個界面Activity
  3. 點擊home主頁按鍵,該應用Application切換到後臺。
  4. 點擊menu菜單按鍵,該應用的當前界面Activity在最近任務欄展現。
  5. 點擊分屏按鍵,該應用Application做爲多窗口模式之一顯示。
  6. 點擊息屏按鍵,該應用Application在後臺休眠。
  7. 點擊電源按鍵,強制關機,該應用Application被殺死。

界面暫停(調用onPause()

當界面運行狀態被改變後,系統都會首先調用onPause()方法,此時系統已中止當前界面Activity與用戶的交互響應操做,官方稱之爲已暫停狀態。能夠重寫該方法,在其中作釋放一些不須要但卻很耗電的系統資源,以防止無效持有消耗電量。可是此時該界面仍然對用戶可見,因此不建議在該方法內執行耗時的釋放操做,以避免給用戶帶來卡頓的假象。

在該狀態以後,Android系統根據以前的用戶操做類型判斷後續生命週期流程。
操做一、二、三、六、7可能會繼續令當前界面Activity中止展現
而操做四、5將可能在用戶從新點擊該界面返回,此時將從新回到界面運行的生命週期中。

界面中止展現(調用onStop()

當系統令當前界面Activiy中止展現時,會調用onStop()方法,將當前界面對用戶不可見,官方稱之爲已中止狀態。重寫該方法時,能夠釋放界面資源和不須要的CPU耗時資源,以供其餘地方及時得到。

在該狀態以後,Android系統繼續根據以前的用戶操做類型判斷後續的生命週期流程。
操做1會將新啓動的界面Activity放入當前Activity所在任務棧中,等待新啓動的界面返回時,令當前界面從新展現
操做2則是將當前界面從任務棧中取出並銷燬
操做3則可能在手機內存不足時,將當前應用的全部界面包括當前界面從任務棧中取出並銷燬
操做6會將當前應用休眠,等設備從新亮屏後,令當前界面從新展現;也可能有的設備在息屏休眠後保持低消耗電源模式時,當前應用超過必定時間或內存佔用的休眠期後,被系統殺死,即當前應用的全部界面包括當前界面從任務棧彙總取出並銷燬
操做7則會將當前應用的全部界面所有銷燬,不會再調用當前界面的任何生命週期。

界面從新展現(調用onRestart()

當界面由用戶不可見轉爲可見時,若是以前已經界面建立了,則會調用onRestart()方法,以代表當前界面將會從新展現。重寫該方法能夠處理對用戶從新可見後的操做。

該方法調用以後,系統將會繼續調用界面展現運行,以從新運行界面與用戶的交互操做。

界面銷燬(調用onDestroy()

當界面Activity被移除任務棧後,若是應用程序還處在Android系統的控制下,系統將在調用onDestroy()方法以後銷燬界面,官方稱之爲已銷燬狀態。重寫此方法能夠釋放全部不須要的資源,以防止發生內存泄漏OOM的問題。


上述內容是針對單個界面Activity的加載流程,那麼其中涉及到的兩個界面Activity的相互交流方式是怎樣的,以及界面運行以後如何處理與用戶的交互操做?詳情請關注後續文章。

相關文章
相關標籤/搜索