生命周期:1.典型情況下的生命周期 :有用戶參與的情況下(當(dāng)然手機的各種狀態(tài)都是理想情況下)
2.異常情況下的生命周期:指的是現(xiàn)實情況下,例如手機內(nèi)容不足献起。Activity被系統(tǒng)回收擂涛,
還有就是當(dāng)前Configuration發(fā)生變化從而導(dǎo)致Activity被銷毀重建等惶我。(Actvity在異常情況下遍希,表現(xiàn)十分微妙授霸。)
1.典型情況下的生命周期:如下圖所示
如下代碼所示:
public classMainActivityextendsAppCompatActivity {
private static finalStringTAG="bill";
@Override
protected voidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG,"onCreate()");
}
@Override
protected voidonRestart() {
super.onRestart();
Log.d(TAG,"onRestart()");
}
@Override
protected voidonStart() {
super.onStart();
Log.d(TAG,"onStart()");
}
@Override
protected voidonResume() {
super.onResume();
Log.d(TAG,"onResume()");
}
@Override
protected voidonPause() {
super.onPause();
Log.d(TAG,"onPause()");
}
@Override
protected voidonStop() {
super.onStop();
Log.d(TAG,"onStop()");
}
@Override
protected voidonDestroy() {
super.onDestroy();
Log.d(TAG,"onDestroy()");
}
}
上面代碼是把activity中所有的生命周期都打印了出來。
那么我們可以看到伴箩,第一次啟動的時候運行順序:
以下就不意義列舉各種正常情況了:
只寫結(jié)果:
1.正常情況下入愧,oncreate() onstart() onresume()
2.如果當(dāng)前activity A打開另一個activity B或點擊home鍵進(jìn)入桌面鄙漏,那么此時執(zhí)行activity A的onpause() onstop()方法嗤谚,當(dāng)然此時有一種特殊的activity B是不會調(diào)用onstop()方法,只是會調(diào)用onpause()方法怔蚌,那就是巩步,此activity B的主題是透明色的。
3.當(dāng)回到activity A的時候桦踊,調(diào)用 onRestart() onstart() onresume()方法
4.當(dāng)activity被系統(tǒng)回收以后再次打開椅野,生命周期的調(diào)用順序和1是一樣的,但是僅僅是生命周期的調(diào)用順序籍胯,并不代表其他過程也一樣竟闪。
5.生命周期配對:oncreate() ondestroy()
onstar() onstop()
onresume() onpause()
那么問題來了:
activity A打開activity B的時候,activity A的onpause()和activity的onResume()方法執(zhí)行的先后順序是怎樣的杖狼?
打印日志可以看出炼蛤,兩個activity調(diào)用的生命周期方法,竟然載同一個線程內(nèi)蝶涩,如圖
從上圖可以看出理朋,activity A的onpause()方法先執(zhí)行絮识,然后執(zhí)行依次activity B的onCreate() onstart() onResume()方法,再去執(zhí)行A的onstop()等方法嗽上。
另一方面次舌,Android官方也說過,不能在onpause中做一些重量級操作兽愤,畢竟要當(dāng)前的activity先執(zhí)行完onpause()才能再執(zhí)行下一個activity的開始生命周期彼念。
2.異常情況下的生命周期
1)資源相關(guān)的activity發(fā)生改變,導(dǎo)致activity被殺死并重建
例子:資源相關(guān)的配置發(fā)生改變浅萧、系統(tǒng)內(nèi)存不足的時候国拇,activity可能會被殺死。
在activity下添加以下方法:
@Override
public voidonSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(OUTSTATE,"我被保存下來了");
Log.d(TAG,"Thread :"+ Thread.currentThread() +",onSaveInstanceState()");
}
@Override
public voidonRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if(savedInstanceState !=null) {
String outstate = savedInstanceState.getString(OUTSTATE);
Log.d(TAG,"onRestoreInstanceState() outstates = "+ outstate);
}
Log.d(TAG,"Thread :"+ Thread.currentThread() +",onRestoreInstanceState()");
}
分析:資源相關(guān)配置發(fā)生改變:
從豎屏轉(zhuǎn)換成橫屏的時候惯殊,日志如下:
從橫屏轉(zhuǎn)換成豎屏的時候酱吝,日志如下:
此時知道,我們的activity如果屏幕旋轉(zhuǎn)土思,會造成生命周期的改變务热,一般來說是這樣:
onpause() -> onsaveinstancestate() -> onstop() -> ondestroy() -> oncreate() -> onstart() -> onrestoreinstancestate() ->onresume()
而且onrestoreinstancestate()能獲取到onsaveinstancestate()保存下來的數(shù)據(jù),并且調(diào)用順序是在onstart()方法之后己儒。
但是崎岂,有一點,日志里邊沒有說明的:onsaveinstancestate()方法的調(diào)用時機是在onstop()之前闪湾,而且又和onpause()沒有時間順序上的關(guān)系冲甘。(待驗證)
值得說明的一個是:在執(zhí)行完activity的onsaveinstancestate()方法之后,還會activity會委托window保存數(shù)據(jù)途样,接著window委托他的頂級容器去保存數(shù)據(jù)江醇,頂層容器是一個viewgroup,然后頂層容器會再去通知他的子元素何暇,例如TextView去調(diào)用它的onsaveinstancestate()方法去保存它的數(shù)據(jù)陶夜。這是一個典型的委托思想,在view的繪制過程和分發(fā)機制中也是用的類似的思想裆站。
當(dāng)系統(tǒng)資源內(nèi)存不足的時候条辟,會由優(yōu)先級從低到高依次kill activity。
這里的優(yōu)先級劃分:前臺展示的activity最高宏胯,可見但非前臺的activity中級羽嫡,后臺activity優(yōu)先級最低。(這時候可以根據(jù)生命周期是否調(diào)用onpause onstop方法判斷優(yōu)先級肩袍,例如最高級是沒有執(zhí)行兩個方法杭棵,中級是之執(zhí)行了onpause方法,最低級是執(zhí)行了兩個方法)
剛才說的第一種情況了牛,當(dāng)屏幕的橫豎屏改變的時候颜屠,activity會重新繪制辰妙,會把生命周期先結(jié)束再重新開始,那么如果我不想重新繪制activity的話甫窟,應(yīng)該怎么做呢密浑?
答:在manifest給需要設(shè)置的activity添加:android:configChanges="orientation",
當(dāng)然在sdk>13的時候還要加上一個屬性scrrenSize,變成:android:configChanges="screenSize|orientation",設(shè)置了當(dāng)前的屬性粗井,顧名思義:這個是配置改變的時候尔破,屏幕的橫豎配置改變的時候。
并且加上下面的代碼:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
switch(newConfig.orientation){
case Configuration.ORIENTATION_LANDSCAPE:
Log.d(TAG,"變成了橫著的");
break;
case Configuration.ORIENTATION_PORTRAIT:
Log.d(TAG,"變成了豎著的");
break;
}
}
當(dāng)屏幕的橫豎改變的時候浇衬,打印日志為: