一.Activity生命周期探討
其實(shí)這張圖已經(jīng)說(shuō)明了activity的生命周期漱病,但是在這里需要的注意的是焙糟,
(1)onCreat是activity正在被創(chuàng)建冕茅,也就是說(shuō)此時(shí)的UI操作不會(huì)更新UI落午,比如setText操作析显,所以此時(shí)在子線程調(diào)用setText不會(huì)報(bào)線程錯(cuò)誤鲫咽。詳解可見(jiàn)Android子線程更新View的探索,在這個(gè)方法內(nèi)我們可以做一些初始化工作。
(2)onRestart需要注意的是:activity正在重新啟動(dòng)谷异,一般情況下分尸,activity從不可見(jiàn)狀態(tài)到可見(jiàn)狀態(tài),onRestart才會(huì)被調(diào)用歹嘹,但是一定要注意的是一般來(lái)說(shuō)這是用戶行為導(dǎo)致activity不可見(jiàn)的時(shí)候箩绍,此時(shí)變?yōu)榭梢?jiàn)的時(shí)候才會(huì)調(diào)用onRestart,這里所說(shuō)的用戶行為就是用戶按home鍵尺上,或者進(jìn)入“新”的activity伶选。這樣的操作會(huì)使activity先執(zhí)行onPause,后執(zhí)行onStop,這樣回到這個(gè)activity會(huì)調(diào)用onRestart尖昏。為什么我這里強(qiáng)調(diào)說(shuō)用戶行為導(dǎo)致的不可見(jiàn)狀態(tài)仰税,等下我會(huì)說(shuō)。抽诉。陨簇。。
(3)onStart的時(shí)候迹淌,activity可見(jiàn)河绽,但是沒(méi)有出現(xiàn)在前臺(tái),無(wú)法與用戶交互
(4)onResume的時(shí)候唉窃,activity已經(jīng)可見(jiàn)耙饰,并且出現(xiàn)在前臺(tái)開(kāi)始活動(dòng),與onStart相比纹份,activity都已經(jīng)可見(jiàn)苟跪,但是onStart的時(shí)候activity還在后臺(tái),onResume才顯示在前臺(tái)
(5)onPause主要注意的是:此時(shí)的activity正在被停止蔓涧,接下來(lái)馬上調(diào)用onStop件已。特殊情況下快速回到該activity,onStop不會(huì)執(zhí)行元暴,會(huì)去執(zhí)行onResume篷扩。
一般在這個(gè)生命周期內(nèi)做存儲(chǔ)數(shù)據(jù)、停止動(dòng)畫(huà)工作茉盏,但不能太耗時(shí)鉴未。
為什么特殊強(qiáng)調(diào)呢枢冤,因?yàn)樵揳ctivity的onPause執(zhí)行完了,才回去執(zhí)行新的activity的onResume铜秆,一旦耗時(shí)掏导,必然會(huì)拖慢新的activity的顯示。
(6)onStop:此時(shí)的activity即將停止羽峰。在這里可以做稍微重量級(jí)的操作,同樣也不能耗時(shí)添瓷。
(7)onDestroy:此時(shí)的activity即將被回收梅屉,在這里會(huì)做一些回收工作和最終資源釋放。
在這里著重講解一下onStart與onRusume鳞贷,onPause與onStop區(qū)別
onStart與onRusume兩種狀態(tài)雖都可見(jiàn)坯汤,但onStart時(shí)還無(wú)法與用戶交互,并未獲得焦點(diǎn)搀愧。onRusume時(shí)頁(yè)面已獲得焦點(diǎn)惰聂,可與用戶交互;onPause時(shí)頁(yè)面還在前臺(tái)咱筛,只不過(guò)頁(yè)面已失去焦點(diǎn)搓幌,無(wú)法與用戶交互了,onStop時(shí)已不可見(jiàn)了迅箩。
activity四個(gè)狀態(tài)所在的生命周期:
- Running狀態(tài):一個(gè)新的Activity啟動(dòng)入棧后溉愁,它在屏幕最前端,處于棧的最頂端饲趋,此時(shí)它處于可見(jiàn)并可和用戶交互的激活狀態(tài)拐揭。
- Paused狀態(tài):依舊在用戶可見(jiàn)狀態(tài),但是界面焦點(diǎn)已經(jīng)失去奕塑,此Activity無(wú)法與用戶進(jìn)行交互堂污。當(dāng)Activity被另一個(gè)透明或者Dialog樣式的Activity覆蓋時(shí)的狀態(tài)。此時(shí)它依然與窗口管理器保持連接龄砰,系統(tǒng)繼續(xù)維護(hù)其內(nèi)部狀態(tài)盟猖,它仍然可見(jiàn),但它已經(jīng)失去了焦點(diǎn)换棚,故不可與用戶交互扒披。所以就解釋為什么啟動(dòng)一個(gè)dialogActivity或者透明Activity時(shí),原Activity只執(zhí)行了onPause生命周期圃泡,并未執(zhí)行onStop
- Stopped狀態(tài):用戶看不到當(dāng)前界面,也無(wú)法與用戶進(jìn)行交互 完全被覆蓋碟案。當(dāng)Activity不可見(jiàn)時(shí),Activity處于Stopped狀態(tài)颇蜡。當(dāng)Activity處于此狀態(tài)時(shí)价说,一定要保存當(dāng)前數(shù)據(jù)和當(dāng)前的UI狀態(tài)辆亏,否則一旦Activity退出或關(guān)閉時(shí),當(dāng)前的數(shù)據(jù)和UI狀態(tài)就丟失了鳖目。
- Killed狀態(tài):Activity被殺掉以后或者被啟動(dòng)以前扮叨,處于Killed狀態(tài)。這是Activity已從Activity堆棧中移除领迈,需要重新啟動(dòng)才可以顯示和使用彻磁。
4種狀態(tài)中,Running狀態(tài)和Paused狀態(tài)是可見(jiàn)的狸捅,Stopped狀態(tài)和Killed狀態(tài)時(shí)不可見(jiàn)的衷蜓。
Activity注意事項(xiàng)
Activity中所有和狀態(tài)相關(guān)的回調(diào)函數(shù):
在這里我會(huì)特別提出一個(gè)point,就是異常情況下activity被殺死尘喝,而后被重新創(chuàng)建的情況磁浇。
這張圖非常重要,可以幫我們解決異常情況下activity如何正承嗤剩回復(fù)的問(wèn)題
當(dāng)系統(tǒng)停止activity時(shí)置吓,它會(huì)調(diào)用onSaveInstanceState()(過(guò)程1),如果activity被銷(xiāo)毀了缔赠,但是需要?jiǎng)?chuàng)建同樣的實(shí)例衍锚,系統(tǒng)會(huì)把過(guò)程1中的狀態(tài)數(shù)據(jù)傳給onCreate()和onRestoreInstanceState(),所以我們要在onSaveInstanceState()內(nèi)做保存參數(shù)的動(dòng)作嗤堰,在onRestoreInstanceState()做獲取參數(shù)的動(dòng)作构拳。
Save Activity State
static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
...
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the user's current game state
savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
獲取參數(shù)操作:
onCreate() 方法
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // Always call the superclass first
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
// Restore value of members from saved state
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
} else {
// Probably initialize members with default values for a new instance
}
...
}
也可以
onRestoreInstanceState()方法
public void onRestoreInstanceState(Bundle savedInstanceState) {
// Always call the superclass so it can restore the view hierarchy
super.onRestoreInstanceState(savedInstanceState);
// Restore state members from saved instance
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}
頁(yè)面切換
橫豎屏切換時(shí) Activity 的生命周期
1、不設(shè)置 Activity 的 android:configChanges 時(shí)梁棠,切屏?xí)匦抡{(diào)用各個(gè)生命周期 默認(rèn)首先銷(xiāo)毀當(dāng)前 activity置森,然后重新加載。如下圖符糊,當(dāng)橫豎屏切換時(shí)先執(zhí)行 onPause/onStop 方法
2凫海、設(shè)置 Activity 的 android:configChanges="orientation|keyboardHidden|screenSize"時(shí),切屏不會(huì)重新調(diào) 用各個(gè)生命周期男娄,只會(huì)執(zhí)行 onConfigurationChanged 方法行贪。
二.Fragment生命周期探討
這張圖很好的說(shuō)明了Fragment與Actvivity生命周期的整合情況。通過(guò)對(duì)Fragment和Activity對(duì)比模闲,將會(huì)發(fā)現(xiàn)許多不同之處建瘫,主要原因是因?yàn)锳ctivity和Fragment之間需要交互。
在這里我首先需要提出的一些points:
- Fragment是直接從Object繼承的尸折,而Activity是Context的子類(lèi)啰脚。因此我們可以得出結(jié)論:Fragment不是Activity的擴(kuò)展。但是與Activity一樣实夹,在我們使用Fragment的時(shí)候我們總會(huì)擴(kuò)展Fragment(或者是她的子類(lèi))橄浓,并可以通過(guò)子類(lèi)更改她的行為粒梦。
- 使用Fragment時(shí),必要構(gòu)建一個(gè)無(wú)參構(gòu)造函數(shù)荸实,系統(tǒng)會(huì)默認(rèn)帶匀们。但一但寫(xiě)有參構(gòu)造函數(shù),就必要構(gòu)建無(wú)參構(gòu)造函數(shù)准给。一般來(lái)說(shuō)我們傳參數(shù)給Fragment泄朴,會(huì)通過(guò)bundle,而不會(huì)用構(gòu)造方法傳露氮,代碼如下:
public static MyFragment newInstance(int index){
MyFragment mf = new MyFragment();
Bundle args = new Bundle();
args.putInt("index",index);
mf.setArguments(args);
return mf;
}
下面來(lái)分析生命周期祖灰,然后根據(jù)這些我會(huì)強(qiáng)調(diào)一些point。
(1)onAttach:onAttach()回調(diào)將在Fragment與其Activity關(guān)聯(lián)之后調(diào)用沦辙。需要使用Activity的引用或者使用Activity作為其他操作的上下文,將在此回調(diào)方法中實(shí)現(xiàn)讹剔。
需要注意的是:將Fragment附加到Activity以后油讯,就無(wú)法再次調(diào)用setArguments()——除了在最開(kāi)始,無(wú)法向初始化參數(shù)添加內(nèi)容延欠。
(2)onCreate(Bundle savedInstanceState):此時(shí)的Fragment的onCreat回調(diào)時(shí)陌兑,該fragmet還沒(méi)有獲得Activity的onCreate()已完成的通知,所以不能將依賴于Activity視圖層次結(jié)構(gòu)存在性的代碼放入此回調(diào)方法中由捎。在onCreate()回調(diào)方法中兔综,我們應(yīng)該盡量避免耗時(shí)操作。此時(shí)的bundle就可以獲取到activity傳來(lái)的參數(shù)
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
if (args != null) {
mLabel = args.getCharSequence("label", mLabel);
}
}
(3)onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState): 其中的Bundle為狀態(tài)包與上面的bundle不一樣狞玛。
注意的是:不要將視圖層次結(jié)構(gòu)附加到傳入的ViewGroup父元素中软驰,該關(guān)聯(lián)會(huì)自動(dòng)完成。如果在此回調(diào)中將碎片的視圖層次結(jié)構(gòu)附加到父元素心肪,很可能會(huì)出現(xiàn)異常锭亏。
這句話什么意思呢?就是不要把初始化的view視圖主動(dòng)添加到container里面硬鞍,以為這會(huì)系統(tǒng)自帶慧瘤,所以inflate函數(shù)的第三個(gè)參數(shù)必須填false,而且不能出現(xiàn)container.addView(v)的操作固该。
View v = inflater.inflate(R.layout.hello_world, container, false);
(4)onActivityCreated:onActivityCreated()回調(diào)會(huì)在Activity完成其onCreate()回調(diào)之后調(diào)用锅减。在調(diào)用onActivityCreated()之前,Activity的視圖層次結(jié)構(gòu)已經(jīng)準(zhǔn)備好了伐坏,這是在用戶看到用戶界面之前你可對(duì)用戶界面執(zhí)行的最后調(diào)整的地方怔匣。
強(qiáng)調(diào)的point:如果Activity和她的Fragment是從保存的狀態(tài)重新創(chuàng)建的,此回調(diào)尤其重要桦沉,也可以在這里確保此Activity的其他所有Fragment已經(jīng)附加到該Activity中了
(5)Fragment與Activity相同生命周期調(diào)用:接下來(lái)的onStart()\onResume()\onPause()\onStop()回調(diào)方法將和Activity的回調(diào)方法進(jìn)行綁定劫狠,也就是說(shuō)與Activity中對(duì)應(yīng)的生命周期相同拴疤,因此不做過(guò)多介紹。
(6)onDestroyView:該回調(diào)方法在視圖層次結(jié)構(gòu)與Fragment分離之后調(diào)用独泞。
(7)onDestroy:不再使用Fragment時(shí)調(diào)用呐矾。(備注:Fragment仍然附加到Activity并任然可以找到,但是不能執(zhí)行其他操作)
(8)onDetach:Fragme生命周期最后回調(diào)函數(shù)懦砂,調(diào)用后蜒犯,F(xiàn)ragment不再與Activity綁定,釋放資源荞膘。
Fragment注意事項(xiàng)
在使用Fragment時(shí)衔沼,我發(fā)現(xiàn)了一個(gè)金礦,那就是setRetainInstance()方法,此方法可以有效地提高系統(tǒng)的運(yùn)行效率椰于,對(duì)流暢性要求較高的應(yīng)用可以適當(dāng)采用此方法進(jìn)行設(shè)置梭姓。
Fragment有一個(gè)非常強(qiáng)大的功能——就是可以在Activity重新創(chuàng)建時(shí)可以不完全銷(xiāo)毀Fragment,以便Fragment可以恢復(fù)屠升。在onCreate()方法中調(diào)用setRetainInstance(true/false)方法是最佳位置潮改。當(dāng)Fragment恢復(fù)時(shí)的生命周期如上圖所示,注意圖中的紅色箭頭腹暖。當(dāng)在onCreate()方法中調(diào)用了setRetainInstance(true)后汇在,F(xiàn)ragment恢復(fù)時(shí)會(huì)跳過(guò)onCreate()和onDestroy()方法,因此不能在onCreate()中放置一些初始化邏輯脏答,切忌糕殉!