Android基礎之Activity全解析

概念

Android四大應用組件之一,與用戶交互的接口,界面的載體。java

生命週期

  • onCreate(),生命週期第一個方法,表示Activity正在建立過程當中。通常作一些初始化工做,setContentView()加載界面佈局等。
  • onStart(),表示Activity正在啓動過程當中,Activity可見但不可與用戶交互。
  • onReStart(),表示Activity正在從新啓動過程當中,通常Activity由不可見到可見過程當中會回調此方法。
  • onResume(),Activity顯示在前臺並可與用戶交互。
  • onPause(),表示Activity正在中止,可作中止動畫,存儲數據操做,不能作耗時操做。
  • onStop(),表示Activity即將中止,可作輕量級回收工做。
  • onDestory(),表示Activity即將銷燬,生命週期最後一個方法。

從整個生命週期來講,onCreate與onDestory是配對的,標誌銷燬與建立,真個生命週期只會回調一次。onStart與onStop是配對的,標誌Activity是否可見。onResume與onPause是配對的,標誌是否處於前臺可與用戶交互。android

onPause不能作太耗時的操做,不然會影響新的Activity的顯示app

  • 首次啓動Activity,系統會先回調onCreate方法而後調用onStart,onResume,Activity進入運行狀態。
  • 當前Activity被其餘Activity覆蓋其上或被鎖屏(能夠理解爲沒有徹底遮擋界面),系統會調用onPause方法,暫停當前Activity的執行。
  • 當前Activity由被覆蓋狀態回到前臺或解鎖屏,系統會調用onResume方法,再次進入運行狀態。
  • 當前Activity轉到新的Activity界面或按Home鍵回到主屏,自身退居後臺,系統會先調用onPause方法,而後調用onStop方法,進入停滯狀態。(若是新Activity採用透明主題,當前Activity不會回調onStop方法)
  • 用戶後退回到此Activity,系統會先調用onRestart方法,而後調用onStart方法,最後調用onResume方法,再次進入運行狀態。
  • 用戶退出當前Activity,系統先調用onPause方法,而後調用onStop方法,最後調用onDestory方法,結束當前Activity。

A Activity啓動B Activity的生命週期狀況: A執行onCreate,onStart,onResume到可交互狀態,此時啓動B Activity,首先將執行A Activity的onpause暫停A Activity執行,而後執行B Activity的onCreate,onStart,onResume到可交互狀態,而後再執行A Activity的onStop方法(若是B Activity未徹底遮擋A Activity, 將不會回調A Activity的onStop方法),若是啓動B Activity時失敗,A Activity將從onPause狀態回到onResume執行。佈局

home鍵/鎖屏生命週期狀況: onPause -> onStop動畫

back鍵/清除recent生命週期狀況: onPause -> onStop -> onDestoryui

異常狀況的銷燬與恢復

當系統「未經用戶許可」銷燬activity時,會回調onSaveInstanceState方法保存數據,讓界面能夠恢復。onSaveInstanceState方法何時會執行?google

  1. 當用戶按下HOME鍵時。系統不知道你按下HOME後要運行多少其餘的程序,天然也不知道activity是否會被銷燬,故系統會調用onSaveInstanceState,讓用戶有機會保存某些非永久性的數據。
  2. 長按HOME鍵,選擇運行其餘的程序時。
  3. 按下電源按鍵(關閉屏幕顯示)時。
  4. 從activity A中啓動一個新的activity時。
  5. 屏幕方向切換時,例如從豎屏切換到橫屏時。

onCreate()裏也有Bundle參數,能夠用來恢復數據,它和onRestoreInstanceState有什麼區別?翻譯

由於onSaveInstanceState 不必定會被調用,因此onCreate()裏的Bundle參數可能爲空,若是使用onCreate()來恢復數據,必定要作非空判斷。而onRestoreInstanceState的Bundle參數必定不會是空值,由於它只有在上次activity被回收了纔會調用。並且onRestoreInstanceState是在onStart()以後被調用的。有時候咱們須要onCreate()中作的一些初始化完成以後再恢復數據,用onRestoreInstanceState會比較方便。onSaveInstanceState調用時機在onStop()前,onRestoreInstanceState的調用時機實在onStart()以後。cdn

注意:xml

onSaveInstanceState方法和onRestoreInstanceState方法「不必定」是成對的被調用的,onRestoreInstanceState被調用的前提是,activity A「確實」被系統銷燬了,而若是僅僅是停留在有這種可能性的狀況下,則該方法不會被調用,例如,當正在顯示activity A的時候,用戶按下HOME鍵回到主界面,而後用戶緊接着又返回到activity A,這種狀況下activity A通常不會由於內存的緣由被系統銷燬,故activity A的onRestoreInstanceState方法不會被執行。

onSaveInstanceState和onRestoreInstanceState方法中,系統自動作了一系列恢復動做,系統會默認保存當前Activity視圖結構,並在Activity重啓後恢復這些數據。Activity被意外終止時,首先會回調onSaveInstanceState保存數據,而後委託Window -> DecorView -> View一層層保存數據。與Activity同樣,每一個View都有onSaveInstanceState和onRestoreInstanceState方法。

啓動模式

任務棧(task stack)

爲了記錄用戶開啓了那些activity,記錄這些activity開啓的前後順序,google引入任務棧(task stack)概念,以棧的結構(先進後出)將依次打開的activity記錄保存在task stack中。

啓動模式

Standard

默認Standard模式,假設沒有爲Activity設置啓動模式的話,默認是標準模式。即每次啓動一個Activity都會又一次建立一個新的實例入棧,不管這個實例是否存在。Standard模式的Activity默認會進入啓動它的Activity所屬的任務棧(啓動它的Activity爲SingleInstance的狀況除外)。

SingleTop

當建立的Activity已經處於棧頂時,此時會直接複用棧頂的Activity,不會再建立新的Activity。若需要建立的Activity不處於棧頂,此時會又一次建立一個新的Activity入棧,同Standard模式同樣。 棧頂的Activity被直接複用時,onCreate、onStart不會被系統調用,而是回調onNewIntent方法(Activity被正常建立時不會回調此方法),而後再執行onResume。(實際是onPause -> onNewIntent -> onResume)

SingleTask

棧內複用模式,若需要建立的Activity已經處於棧中時,此時不會建立新的Activity,而是將存在棧中的Activity上面的其餘Activity全部銷燬,使它成爲棧頂。 同SingleTop模式中同樣,onCreate、onStart不會被系統調用,僅僅回調Activity中的onNewIntent方法。

好比啓動Activity A,先找其對應的任務棧,若是不存在,則先新建任務棧,在建立Activity A放到任務棧中。若是存在,則判斷棧中是否存在Activity A的實例,若是存在則把Activity A調到棧頂,而後調用其onNewIntent方法。若是不存在Activity A的實例,則新建Activity A放到任務棧中。

SingleTask會致使它之上的棧內全部Activity出棧

SingleInstance

具備此模式的Activity僅僅能單獨位於一個任務棧中

taskAffinity

taskAffinity,能夠翻譯爲任務相關性。這個參數標識了一個 Activity 所須要的任務棧的名字,默認狀況下,全部 Activity 所需的任務棧的名字爲應用的包名,當 Activity 設置了 taskAffinity 屬性,那麼這個 Activity 在被建立時就會運行在和 taskAffinity 名字相同的任務棧中,若是沒有,則新建 taskAffinity 指定的任務棧,並將 Activity 放入該棧中。另外,taskAffinity 屬性主要和singleTask或者allowTaskReparenting屬性配對使用,在其餘狀況下沒有意義。

  • taskAffinity對Standard與SingleTop,SingleInstance沒有影響
  • taskAffinity對SingleTask的影響: 以A啓動B來講 當A和B的taskAffinity相同時:第一次建立B的實例時,並不會啓動新的task,而是直接將B添加到A所在的task;當B的實例已經存在時,將B所在task中位於B之上的所有Activity都移除,B就成爲棧頂元素,實現跳轉到B的功能。 當A和B的taskAffinity不一樣時:第一次建立B的實例時,會啓動新的task,而後將B添加到新建的task中;當B的實例引進存在,將B所在task中位於B之上的所有Activity都移除,B就成爲棧頂元素(也是root Activity),實現跳轉到B的功能。

使用場景

  • Standard 普通狀況下使用
  • SingleTop 適用於同類型的Activity,例如通知欄消息接收啓動的Activity
  • SingleTask 主界面
  • SingleInstance 適合公開成通用功能的Activity,例如撥號,鬧鐘界面等

Activity Flags

  1. FLAG_ACTIVITY_NEW_TASK 做用是爲Activity指定 「SingleTask」啓動模式。跟在AndroidMainfest.xml指定效果一樣。

注意: FLAG_ACTIVITY_NEW_TASK與FLAG_ACTIVITY_CLEAN_TOP才具有AndroidMainfest.xml指定SingleTask一樣效果

  1. FLAG_ACTIVITY_SINGLE_TOP 做用是爲Activity指定 「SingleTop」啓動模式,跟在AndroidMainfest.xml指定效果一樣。

  2. FLAG_ACTIVITY_CLEAN_TOP 具備此標記位的Activity,啓動時會將與該Activity在同一任務棧的其餘Activity出棧。通常與SingleTask啓動模式一塊兒出現。它會完畢SingleTask的做用。但事實上SingleTask啓動模式默認具備此標記位的做用

  3. FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 具備此標記位的Activity不會出現在歷史Activity的列表中,使用場景:當某些狀況下咱們不但願用戶經過歷史列表回到Activity時,此標記位便體現了它的效果。它等同於在xml中指定Activity的屬性:android:excludeFromRecents="trure"

相關

  1. Activity因系統內存不足被Kill或是由於Crash閃退的異常退出怎麼保存數據? Activity被銷燬了之後調用了onSaveInstanceState來保存數據,這個只會在Activity即將銷燬而且有機會從新顯示的狀況下才會去調用onSaveInstanceState,與之配對的是在onRestoreInstanceState裏恢復數據。

  2. 資源不足時Activity的殺死順序

    • 前臺Activity,正在和用戶交互的Activity,優先級最高
    • 可見但非前臺Activity,好比Activity中彈出了一個對話框,致使Activity可見可是位於後臺沒法和用戶直接交互。
    • 後臺Activity,已經被暫停的Activity,好比執行了onStop,優先級最低
  3. 橫豎屏切換時候Activity的生命週期 跟Manifest配置有關

    • 不設置Activity的android:configChanges時,切屏會從新調用各個生命週期默認首先銷燬當前activity,而後從新建立
    • 設置Activity的android:configChanges="orientation|screenSize"時,切屏不會從新調用各個生命週期,只會執onConfigurationChanged方法
  4. 啓動其餘應用Activity時,報java.lang.SecurityException: Permission Denial,由於在其餘應用StartActivity時,有去檢驗permission。

知足如下條件,能夠成功startActivity,不會出現permission denial:

  • 同一個application下
  • Uid相同
  • permission匹配
  • 目標Activity的屬性Android:exported=」true」
  • 目標Activity具備相應的IntentFilter,存在Action動做或其餘過濾器而且沒有設置exported=false
  • 啓動者的Pid是一個System Server的Pid
  • 啓動者的Uid是一個System Uid(android.system.uid=1000)
相關文章
相關標籤/搜索