0. 提問

  • onStart和onResume有什麼區別?onPause和onStop有什麼區別?打開一個新Activity時的回調順序?
  • 4種啟動模式的含義?
  • 任務棧的作用?Activity一定會放入其taskAffinity屬性所聲明的棧中嗎?

一. 生命週期

1. 順序

Activity Lifecycle 2. 詳細作用
  • onCreate:生命週期內只調用1次,用於初始化界面、必要對象創建、基礎邏輯、恢複數據、註冊廣播等
  • onStart:界面由完全不可見(不包括被透明界面遮擋)變為可見時調用,利用這個特性處理一些業務邏輯
  • onResume:界面可點擊交互,不被頂層其他任何Activity遮擋;開始執行界面交互操作
  • onPause:界面不可點擊交互,被其他Activity遮擋,部分可見;此時應當停止交互相關等耗資源的操作,如動畫、相機等
  • onStop:界面完全不可見;保存重要數據,而不在onDestroy中執行,因為Activity在後臺時進程被殺,則不調用
  • onDestroy:生命週期內只調用1次,界面完全銷毀,用於執行資源釋放、反註冊廣播等
  • onRestart:界面由stopped狀態下被再次打開時調用

Tips:註冊、反註冊應當在成對的生命週期回調方法裏執行

3. onStart和onResume?

onStart和onResume都是可見,區分在於onResume可點擊交互,用戶可以操作界面。 4. onPause和onStop?
  • 當從Activity A打開一個透明屬性的Activity B時,A只會調用onPause方法,而onStop不會調用。此時,A處於部分可見狀態,但不可交互。同理,此時按返回鍵關閉B返回A,只會調用A的onResume方法。
  • 從A打開B,若B不帶透明屬性:方法調用順序如下:A.onPause → B.onCreate → B.onStart(B開始可見)→ B.onResume → A.onStop。所以兩個方法還是有所區分側重的,兩個方法都不當做耗時操作,特別是onPause方法,會影響界面B的打開,所以稍微重點的計算操作方到onStop中,耗時的當然是非同步處理。

5. 異常狀態下的生命週期

1. 系統配置改變 如屏幕旋轉、鍵盤、語言等等,會觸發Activity重新創建。若想要這些改變時,不觸發Activity重啟,可以通過在AndroidManifest裏設置activity的configChanges屬性。常用的有locale(語言區域)、orientation(屏幕方向)、keyboardHidden(鍵盤無障礙功能)、screenSize(當前可用屏幕尺寸發生了變化,旋轉屏幕尺寸會觸發)。具體參照官網API指南。 2. 系統資源不足 Activity優先順序從高到低,分3種: Ⅰ. 前臺:可交互

Ⅱ. 可見非前臺:比如打開了一個對話框或者透明Activity

Ⅲ. 後臺:跳轉其他Activity 內存不足時,從低到高進行銷毀。 二. 狀態保存與恢復 當Activity跳轉到其他Activity,或者按Home鍵後,在後臺由於資源不足被系統回收,再次打開時若想恢復原有的數據,則需要通過Bundle進行數據存儲與恢復。
  • 保存狀態:在onStop方法之前,系統會調用onSaveInstanceState方法,在此處存儲狀態。
  • 恢復狀態:在onCreate方法裏進行恢復,要先對參數savedInstanceState進行判空。也可以在onRestoreInstanceState方法裏進行恢復,該方法在onStart之後調用,並且只有數據需要恢復時系統才會調用,所以此處savedInstanceState無需判空。

三. LaunchMode-啟動模式

1. 設置方法
  1. AndroidMenifest配置:無法設置FLAG_ACTIVITY_CLEAR_TOP標識
  2. 代碼中設置intent.addFlags():若與第一種同時存在,則以本方式為準。無法設置singleInstance模式

2. Activity任務棧

  • 用於組合存放Activity
  • 採用「後進先出」的棧結構
  • 棧的拼接:從棧A啟動棧B後,按返回鍵,則先將棧B回退到空之後,再進入棧A。可見圖示

棧的拼接

棧拼接後,不代表兩個棧都合併了,只是返回棧拼接而已。如上圖,處於第二步時,若按Home鍵返回桌面,再按多任務鍵打開綠色的任務棧,這時候兩個任務棧不再拼接,按返回鍵後,退出綠色的棧後返回桌面。同理,若多任務鍵切換到藍色的棧,棧的頂部也不會有綠色的棧的內容。

Home鍵回桌面打開應用、多任務鍵切換任務棧,都是直接打開目標任務棧,之前的棧的拼接都會失效。

  • 查看信息命令: adb shell dumpsys activity

3. LaunchMode的4種類型

  1. standard:標準模式:每次啟動一個Activity都會創建一個新的實例,並加入到當前任務棧的頂部
  2. singleTop:棧頂復用模式:若打開的Activity位於即將放入的棧的頂部,則復用,不會創建新的實例。按照onPause → onNewIntent → onResume的順序觸發,可以onNewIntent內處理業務。
  3. singleTask:棧內復用模式:Activity A在棧S1,若A打開B(singleTask)
  • B目標棧為S2,S2不存在:則創建S2,並將B加入到棧中。standard和singleTop不具備該特性。
  • B目標棧為S1(或S2),S1(或S2)存在,棧內無B:創建B放入棧頂。
  • B目標棧為S1(或S2),S1(或S2)存在,棧內有B:復用B,清空B之上的Activity,回調onNewIntent方法。
  1. singleInstance:單實例模式:單獨位於一個任務棧中,棧中不會有其他Activity,單例,你懂的,還是onNewIntent。

4. 標識Flags

  • FLAG_ACTIVITY_NEW_TASK:效果不等同於"singleTask"!!!(《Android開發藝術探索》此書對於這點有誤)

驗證方式:Manifest中配置為singleTask的Activity,通過一個application的context來啟動一個聲明為singleTask的Activity來進行測試,會報錯。因為在解析目標Activity屬性之前,系統對context進行檢測,導致報錯,位於源碼中的ContextImpl.startActivity方法中。

正確理解如下(通過源碼理解測試):

  • 打開的Activity的目標棧如果不存在,則創建棧,並且把Activity放到棧中。
  • 打開的Activity的目標棧如果存在,則再分兩種情況:
    • Activity未打開過:創建Activity放入棧頂;
    • Activity已經打開過(無論是否被銷毀):
      • 若Activity不在棧頂,只會將該棧移動到前臺,不會創建新的Activity。(比如A、B同個目標棧,先打開A,A打開B,此時若B打開A,則是沒有反應的,不會跳轉到A);
      • 若Activity在棧頂,且是使用Standard模式,則會創建新的Activity實例加到棧頂。

  • FLAG_ACTIVITY_SINGLE_TOP:效果如"singleTop"
  • FLAG_ACTIVITY_CLEAR_TOP:singleTask自帶該效果。

特別組合:被啟動的Activity使用standard模式,則會將它以及它以上的Activity都出棧,創建新的Activity放入棧中。

  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:不出現在多任務列表中。

5. 應該進入哪個任務棧?(難點)

  1. taskAffinity:官方翻譯為親和關係,而非棧名,表示更傾向於進入哪個棧。所以不是設置了該屬性的Activity,就是在屬於這個名的棧中
  2. taskAffinity不設置時,則默認為包名;設置為空,則為當前Activity的包名路徑
  3. 當A啟動一個聲明為standard、singleTop的B時,且不帶FLAG_ACTIVITY_NEW_TASK,則只會加入到A所在的棧頂,不會加入B所配置taskAffinity所聲明的棧頂。
  4. 不嚴謹的概括:只有singleTask、singleInstance或者帶FLAG_ACTIVITY_NEW_TASK等帶創建棧能力的方式啟動,才會讓taskAffinity生效。
  5. allowTaskReparenting這個屬性,也會讓taskAffinity生效。比如棧S1中的A啟動設置了taskAffinity的B,無論B使用使用什麼啟動模式,B都會被放入其taskAffinity所聲明的棧。

    小編給大家準備了安卓進階學習資料

    關注+後臺私信「資料」即可獲取

推薦閱讀:

相關文章