生命周期精续,就是一個對象從創(chuàng)建到銷毀的過程挠唆,每一個對象都有自己的生命周期。同樣雹仿,
Activity
也具有相應(yīng)的生命周期增热,在Activity
的生命周期中分為四種狀態(tài),分別是運行狀態(tài)盅粪、暫停狀態(tài)钓葫、停止?fàn)顟B(tài)和銷毀狀態(tài)。
而Activity
從一種狀態(tài)轉(zhuǎn)變到另一種狀態(tài)時會觸發(fā)一些事件票顾,執(zhí)行一些回調(diào)方法來通知狀態(tài)的變化础浮,在這里Activity
類提供了六個核心回調(diào):onCreate()、onStart()奠骄、onResume()豆同、onPause()、onStop()
和onDestroy()
含鳞。當(dāng)Activity
進入新狀態(tài)時影锈,系統(tǒng)會調(diào)用其中每個回調(diào)。
一. Activity 運行狀態(tài)
1. 基本狀態(tài)
-
運行狀態(tài)(Running)當(dāng)
Activity
在屏幕的最前端時蝉绷,它是可見的鸭廷、有焦點的。能夠?qū)崿F(xiàn)用戶交互熔吗,如點擊辆床、雙擊、長按事件等桅狠。 -
暫停狀態(tài)(Paused) 失去焦點因此不可與用戶進行交互讼载,但與窗口管理器保持連接狀態(tài),狀態(tài)性和成員變量依然存在中跌。例如咨堤,當(dāng)最上面的
Activity
沒有完全覆蓋屏幕或者是透明的,被覆蓋的Activity
仍然對用戶可見漩符,并且存活(它保留著所有的狀態(tài)和成員信息并保持與Activity
管理器的連接)一喘。但當(dāng)內(nèi)存不足時,這個暫停狀態(tài)的Activity
可能會被殺死嗜暴。 -
停止?fàn)顟B(tài)(Stopped) 當(dāng)
Activity
完全不可見時凸克,它就處于停止?fàn)顟B(tài)铝侵,但仍然保留著當(dāng)前狀態(tài)和成員信息。只是不可見的触徐,但當(dāng)系統(tǒng)內(nèi)存不足時,這個Activity
很容易被殺死狐赡。 - 銷毀狀態(tài)(Killed)界面被系統(tǒng)回收后撞鹉,處于銷毀狀態(tài),當(dāng)該界面需要再次顯示與用戶交互時颖侄,需要重新開始并重置鸟雏。
值得一提的是,當(dāng) Activity 處于運行狀態(tài)時览祖,Android 會盡可能地保持它的運行孝鹊,
即使出現(xiàn)內(nèi)存不足的情況,Android 也會先殺死棧底部的 Activity展蒂,來確庇只睿可見的 Activity 正常運行。
2. 狀態(tài)轉(zhuǎn)換
當(dāng)一個 Activity
實例被創(chuàng)建锰悼、銷毀或者啟動另外一個 Activity
時柳骄,它在這四種狀態(tài)之間進行轉(zhuǎn)換,這種轉(zhuǎn)換的發(fā)生依賴于用戶程序的動作箕般。下圖說明了 Activity
在不同狀態(tài)間轉(zhuǎn)換的時機和條件:
二. Activity生命周期
從圖中可以看出耐薯,當(dāng)
Activity
從啟動到關(guān)閉時,會依次執(zhí)行
onCreate() → onStart() → onResume() → onPause() → onStop() → onDestroy()
當(dāng) Activity
執(zhí)行到 onPause()
方法失去焦點時丝里,重新調(diào)用回到前臺會執(zhí)行 onResume()
方法曲初,如果此時進程被殺死 Activity
重新執(zhí)行時會先執(zhí)行 onCreate()
方法。當(dāng)執(zhí)行到 onStop()
方法 Activity
不可見時杯聚,再次回到前臺會執(zhí)行 onRestart()
方法臼婆,如果此時進程被殺死 Activity
會重新執(zhí)行 onCreate()
方法。
1. 常用生命周期
方法名 | 簡介 |
---|---|
onCreate | 表示 Activity 正在被創(chuàng)建械媒,這也是 Activity 的生命周期的第一個方法目锭。 |
onRestart | 表示 Activity 正在重新啟動,此生命周期只有在 onPause 與onStop 都執(zhí)行過才會被調(diào)用 |
onStart | 表示 Activity 正在被啟動纷捞,即將開始痢虹,此時 Activity 已經(jīng)可見但是還沒有出現(xiàn)在前臺,還無法交互 |
onResume | 表示 Activity 已經(jīng)可見并出現(xiàn)在前臺可以與用戶進行交互 |
onPause | 表示 Activity 正在停止 |
onStop | 表示 Activity 停止并不可見 |
onDestroy | 表示 Activity 即將被銷毀主儡,這是 Activity 的最后一個回調(diào) |
2. Activity 生命周期切換過程
(1)單 Activity
-
Activity
第一次啟動奖唯,回調(diào)如下:onCreate -> onStart -> onResume
。
- 打開新
Activity
或按Home
鍵:onPause->onStop
糜值。
- 再次回到 Activity:
onRestart->onStart->onResume
丰捷。
- 如果新的
Activity
的Theme
為Dialog
或者Translucent
(透明)時不會調(diào)用onStop
方法坯墨。
- 按
Back
鍵退出Activity
:onPause->onStop->onDestroy
。
注:一般這里只會走 onPause() 和 onStop()病往,當(dāng)把 app 殺死時捣染,才會調(diào)用 onDestrroy()。
(2)ActivityA 啟動 ActivityB
正常情況下:
返回 ActivityA:
(3)Theme 為 Dialog 或 Translucent
ActivityA 啟動 ActivityC:
返回 ActivityA:
(4)旋轉(zhuǎn)屏幕橫豎屏切換(未指定 configChanges)
Activity 正常運行停巷,此時旋轉(zhuǎn)屏幕:
當(dāng)系統(tǒng)配置被更改時 Activity
會被銷毀并重新創(chuàng)建耍攘,Activity
的 onPause、onStop畔勤、onDestroy
均會被調(diào)用蕾各,同時由于 Activity
是異常情況下終止并銷毀的系統(tǒng)會調(diào)用 onSaveInstanceState
方法來保存當(dāng)前 Activity
的狀態(tài)。
**注意**:當(dāng)用戶顯式關(guān)閉 Activity 時庆揪,或者在其他情況下調(diào)用 `finish()` 時式曲,
系統(tǒng)不會調(diào)用 onSaveInstanceState()。
也就是說缸榛,系統(tǒng)在“未經(jīng)你許可”銷毀 Activity 時調(diào)用 onSaveInstanceState 方法吝羞,用于保存 Activity 狀態(tài)信息。
什么時候調(diào)用 onSaveInstanceState 方法:
(1) 當(dāng)用戶按下 HOME 鍵時仔掸。
(2) 切換到其他進程時脆贵。
(3) 鎖屏?xí)r。
(4) 啟動新的 Activity 時起暮。
(5) 屏幕方向切換時卖氨。
什么時候調(diào)用 onRestoreInstanceState 方法:
在 Activity 被系統(tǒng)銷毀,又回到該 Activity 的時候负懦。如用戶按下 HOME 鍵又馬上返回該 Activity筒捺,
這個時候該 Activity 一般不會因為內(nèi)存不足而被系統(tǒng)回收,故不調(diào)用 onRestoreInstanceState 方法纸厉。
所以 onSaveInstanceState 與 onRestoreInstanceState 不一定會成對被調(diào)用系吭。
之后就是正常的啟動流程,當(dāng)然會有 onRestoreInstancesState
方法在 onStart
與 onResume
之間調(diào)用用以恢復(fù) onSaveInstanceState
保存的狀態(tài)颗品。
onSaveInstancesState
調(diào)用時期從 Build.VERSION_CODES.P
開始在 onStop
方法之后調(diào)用肯尺;對于面向較早平臺版本的應(yīng)用程序,此方法將在onStop()
之前發(fā)生躯枢,鏈接则吟。
接下來用 onSaveInstance()
與 onRestoreInstanceState()
來保存與恢復(fù)數(shù)據(jù)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("ActivityA 生命周期", "onCreate()");
if (savedInstanceState != null) {
Log.d("ActivityA 生命周期", "from onContext:" + savedInstanceState.getString("text"));
}
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("text","數(shù)據(jù)");
Log.d("ActivityA 生命周期", "onSaveInstanceState()");
Log.d("ActivityA 生命周期", "數(shù)據(jù)已保存:"+"數(shù)據(jù)");
}
@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.d("ActivityA 生命周期", "onRestoreInstanceState()");
Log.d("ActivityA 生命周期", "from onRestoreInstancesState() 的值為:" + savedInstanceState.getString("text"));
}
我們可以在 onCreate()
和 onRestoreInstanceState()
方法進行數(shù)據(jù)的恢復(fù)處理,onCreate()
中有一個參數(shù)锄蹂,此參數(shù)就是 onSaveInstanceState()
保存的值氓仲,在 onCreate()
中需要對該參數(shù)進行空判斷因為此參數(shù)在 onCreate()
正常啟動的情況下是為 null
的,至于 onRestoreInstanceState()
這個方法不用進行空值判斷因為此方法只要被調(diào)用它的值不可能為空,代碼效果如下敬扛。
(5)資源內(nèi)存不足導(dǎo)致低優(yōu)先級 Activity 被殺死
Activity 優(yōu)先級
- 前臺
Activity
用戶正在交互的Activity
晰洒,優(yōu)先級最高; - 可見但非前臺
Activity
啥箭; - 后臺
Activity
已經(jīng)被停止的Activity
谍珊,例如執(zhí)行了onStop
方法,優(yōu)先級最低急侥。
當(dāng)系統(tǒng)內(nèi)存不足時會按照上面的優(yōu)先級進行銷毀抬驴,并通過 onSaveInstanceState()
和 onRestoreInstanceState()
來存儲與恢復(fù)數(shù)據(jù)。
防止 Activity 被重新創(chuàng)建
當(dāng)某項內(nèi)容被改變時不想停止并重新創(chuàng)建 Activity
可以通過在 AndroidManifest
清單文件中對該 Activity
指定 configChanges
屬性來防止重新創(chuàng)建:
比如旋轉(zhuǎn)屏幕時不想重新創(chuàng)建 Activity 可以指定 orientation 這個屬性值缆巧,
如:android:configChanges="orientation",
如果想指定多個值可以用 “|” 來連接起來如:
android:configChanges="orientation|keyboardHidden"
一些 configChanges
屬性:
在指定 configChanges
之后 Activity
在該系統(tǒng)配置改變的情況下不會重新創(chuàng)建 Activity
也不會調(diào)用 onSaveInstanceState()
或 onRestoreInstanceState()
來保存或恢復(fù)數(shù)據(jù),取而代之的是使用 onConfigurationChanged()
方法豌拙。
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.d("ActivityA 生命周期", "onConfigurationChanged()");
}
三. Activity 四種啟動模式
standard 模式:
standard
模式是Android
的默認啟動模式陕悬,你不在配置文件中作任何設(shè)置,那么這個Activity
就是standard
模式按傅,這種模式下捉超,Activity
能夠有多個實例,每次啟動Activity
唯绍,不管任務(wù)棧中是否已經(jīng)有這個Activity
的實例拼岳,系統(tǒng)都會建立一個新的Activity
實例。SingleTop 模式:
SingleTop
模式和standard
模式很是類似况芒,主要區(qū)別就是當(dāng)一個SingleTop
模式的Activity
已經(jīng)位于任務(wù)棧的棧頂惜纸,再去啟動它時,不會再建立新的實例,若是不位于棧頂绝骚,就會建立新的實例耐版。singleTask模式:
singleTask
模式的Activity
在同一個Task
內(nèi)只有一個實例,若是Activity
已經(jīng)位于棧頂压汪,系統(tǒng)不會建立新的Activity
實例粪牲,和singleTop
模式同樣。但Activity
已經(jīng)存在但不位于棧頂時止剖,系統(tǒng)就會把該Activity
移到棧頂腺阳,并把它上面的Activity
出棧。singleInstance 模式:
singleInstance
模式也是單例的穿香,但和singleTask
不一樣亭引,singleTask
只是任務(wù)棧內(nèi)單例,系統(tǒng)里是能夠有多個singleTask Activity
實例的扔水,而singleInstance Activity
在整個系統(tǒng)里只有一個實例痛侍,啟動singleInstance Activity
時,系統(tǒng)會建立一個新的任務(wù)棧,而且這個任務(wù)棧只有他一個Activity
主届。
四. OnNewIntent()
當(dāng) Activity
被設(shè)以 singleTop
模式啟動赵哲,當(dāng)需要再次響應(yīng)此 Activity
啟動需求時,會復(fù)用棧頂?shù)囊延?Activity
君丁,還會調(diào)用 onNewIntent()
枫夺。并且,再接受新發(fā)送來的 intent(onNewIntent())
之前绘闷,一定會先執(zhí)行 onPause()
橡庞,如下圖所示:
1. onNewIntent() 與啟動模式
前提: ActivityA 已經(jīng)啟動過,處于當(dāng)前應(yīng)用的 Activity 任務(wù)棧中;
(1)當(dāng) ActivityA 的 LaunchMode 為 standard 時:
由于每次啟動 ActivityA
都是啟動新的實例,和原來啟動的沒關(guān)系印蔗,所以不會調(diào)用原來 ActivityA
的 onNewIntent()
扒最。
(2)當(dāng) ActivityA 的 LaunchMode 為 SingleTop 時:
如果 ActivityA
在棧頂,且現(xiàn)在要再啟動 ActivityA
,這時會調(diào)用onNewIntent()
华嘹,生命周期順序為:
(3)當(dāng) ActivityA 的 LaunchMode 為 singleInstance吧趣,singleTask:
如果 ActivityA
已經(jīng)在任務(wù)棧中,再次啟動 ActivityA
耙厚,那么此時會調(diào)用 onNewIntent()
强挫,生命周期調(diào)用順序為:
因此:onNewIntent()
在情況 1
不調(diào)用薛躬,在情況 2
和 3
調(diào)用俯渤。
更準(zhǔn)確的說法是,只對 singleTop
(且位于棧頂)型宝,singleTask
和 singleInstance
(且已經(jīng)在任務(wù)棧中存在實例)的情況下八匠,再次啟動它們時才會調(diào)用,即只對 startActivity
有效趴酣,對僅僅從后臺切換到前臺而不再次啟動的情形臀叙,不會觸發(fā) onNewIntent()
。
五. Fragment 生命周期
Fragment
從Android v3.0
版本開始引入的价卤,隨著界面布局的復(fù)雜化劝萤,處理起來也更加的復(fù)雜,引入Fragment
可以把Activity
拆分成多個部分慎璧。一個Activity
可以同時組合多個Fragment
床嫌,一個Fragment
也可被多個Activity
復(fù)用。Fragment
可以響應(yīng)自己的輸入事件胸私,并擁有自己的生命周期厌处,但它們的生命周期直接被其所屬的Activity
的生命周期控制。
1. Fragment 狀態(tài)
Fragment
狀態(tài)與 Activity
類似岁疼,也存在如下 4
種狀態(tài):
- 運行:當(dāng)前
Fmgment
位于前臺阔涉,用戶可見缆娃,可以獲得焦點。 - 暫停:其他
Activity
位于前臺瑰排,該Fragment
依然可見贯要,只是不能獲得焦點。 - 停止:該
Fragment
不可見椭住,失去焦點崇渗。 - 銷毀:該
Fragment
被完全刪除,或該Fragment
所在的Activity
被結(jié)束京郑。
2. 生命周期狀態(tài)
Fragment
的生命周期與 Activity
的生命周期十分相似宅广,如下圖所示:
可以看到
Fragment
的生命周期和 Activity
很相似,只是多了一下幾個方法:onAttach()些举,onCreateView()跟狱,onActivityCreated(),onDestroyView()
和 onDetach()
户魏。
再來看一下它的常用生命周期:
方法名 | 簡介 |
---|---|
onAttach() | 當(dāng) Fragment 與 Activity 發(fā)生關(guān)聯(lián)時調(diào)用兽肤。 |
onCreate() | 創(chuàng)建 Fragment 時被回調(diào)。 |
onCreateView() | 每次創(chuàng)建绪抛、繪制該 Fragment 的 View 組件時回調(diào)該方法,F(xiàn)ragment 將會顯示該方法返回的 View 組件电禀。 |
onActivityCreated() | 當(dāng) Fragment 所在的 Activity 被啟動完成后回調(diào)該方法幢码。 |
onStart() | 啟動 Fragment 時被回調(diào),此時 Fragment 可見尖飞。 |
onResume() | 恢復(fù) Fragment 時被回調(diào)症副,獲取焦點時回調(diào)。 |
onPause() | 暫停 Fragment 時被回調(diào)政基,失去焦點時回調(diào)贞铣。 |
onStop() | 停止 Fragment 時被回調(diào),F(xiàn)ragment 不可見時回調(diào)沮明。 |
onDestroyView() | 銷毀與 Fragment 有關(guān)的視圖辕坝,但未與 Activity 解除綁定。 |
onDestroy() | 銷毀 Fragment 時被回調(diào)荐健。 |
onDetach() | 與 onAttach() 相對應(yīng)酱畅,當(dāng) Fragment 與 Activity關(guān)聯(lián)被取消時調(diào)用。 |
3. 生命周期調(diào)用
Fragment 生命周期調(diào)用
(1)創(chuàng)建 Fragment
(2)按下 Home
鍵回到桌面 / 鎖屏
(3)從桌面回到 Fragment
/ 解鎖
(4)按下 Back 鍵退出
Activity 和 Fragment 生命周期調(diào)用
- 打開頁面
- 按下主屏幕鍵
- 重新打開頁面
-
按后退鍵
按后退鍵
Fragment
生命周期與 Activity
生命周期的一個關(guān)鍵區(qū)別就在于江场,Fragment
的生命周期方法是由托管 Activity
而不是操作系統(tǒng)調(diào)用的纺酸。Activity
中生命周期方法都是 protected
,而 Fragment
都是 public
址否,也能印證了這一點餐蔬,因為 Activity
需要調(diào)用 Fragment
那些方法并管理它。
Fragment 和 Fragment 生命周期調(diào)用
FragmentA
切換到 FragmentB
時變化:
(1)通過 add hide show
方式來切換
-
FragmentA 的生命周期變化為:
回調(diào)onHiddenChanged()
方法; -
FragmentB 的生命周期變化為:
onCreate() --> onCreateView() --> onActivityCreated() --> onStart() --> onResume()
樊诺; -
FragmentB 再次返回到 FragmentA:
不走任何生命周期方法但是回調(diào)onHiddenChanged()
方法
當(dāng)以這種方式進行 FragmentA 與 FragmentB 的切換時仗考,
Fragment 隱藏的時候并不走 onDestroyView,
所有的顯示也不會走 onCreateView 方法啄骇,所有的 view 都會保存在內(nèi)存痴鳄。
(2)使用 replace
的方法進行切換時
載入FragmentA 時:
FragmentA
的生命周期:onCreate() --> onCreateView() --> onActivityCreated() --> onStart() --> onResume()
-
切換到FragmentB 時:
FragmentA
的生命周期:onPause() --> onStop() --> onDestroyView() --> onDestroy() --> onDetach()
FragmentB
的生命周期:onCreate() --> onCreateView() --> onActivityCreated() --> onStart() --> onResume()
如下圖:
切換到FragmentB 時 FragmentB 切換回 FragmentA 時:
FragmentB
的生命周期:onPause() --> onStop() --> onDestroyView() --> onDestroy() --> onDetach()
FragmentA
的生命周期:onCreate() --> onCreateView() --> onActivityCreated() --> onStart() --> onResume()
注:通過 replace 方法進行替換的時,F(xiàn)ragment 都是進行了銷毀缸夹,
重建的過程痪寻,相當(dāng)于走了一整套的生命周期
(3)使用 ViewPager
進行切換時
當(dāng)使用 ViewPager
與 Fragment
進行切換時,Fragment
會進行預(yù)加載操作虽惭。
- 所有的 Fragment 都會提前初始--->預(yù)加載橡类;
-
初始化時 Fragment 們的生命周期:
FragmentA
的生命周期:onCreate() --> onCreateView() --> onActivityCreated() --> onStart() --> onResume()
FragmentB
的生命周期:同上
-
FragmentA 切換到 FragmentB 的生命周期:
FragmentA
:走setUserVisVleHint()
方法;
FragmentB
:同上
芽唇。
切回去也是一樣的顾画。