1.正常情況下的生命周期
1.onCreate: 與onDestory
配對,表示Activity
被創建,這是生命周期的第一個方法。在這方法中可以做一個初始化的工作(比如加載布局資源,初始化activity所需要的數據等),耗時的工作在異步線程上完成。
2.onRestart:表示Activity
正在重新啟動一般情況下,在當前Actiivity
從不可見重新變為可見狀態時onRestart
就會被調用。這種請求一般都是用戶行為所導致的,比如用戶按下Home鍵切換到桌面或者打開了一個新的Activity
(這時當前的Activity會暫停,也就是onPause和onStop被執行),接著用戶回到了這個Activity
就會出現這種情況。
3.onStart: 與onStop
配對,表示Activity
正在被啟動,并且即將開始。但是這個時候要注意他與onResume
的區別,兩者都標識Avtivity
可見,但是onStart
時Activity
還在加載其他內容,正在像我們展示,用戶還無法看到,即無法交互。
4.onResume:與onPause
配對,表示Activity
已經創建完成,并可以開始活動了,這個時候用戶可以看到界面,并且即將與用戶交互 (完成該周期之后便可以響應用戶的交互事件了)。
5.onPause:與onResume
配對,表示Activity正在暫停,正常情況下,onStop
接著就會被調用,在特殊情況下,如果這個時候用戶快速的再回到當前Activity
,那么onResume
會被調用(極端情況),一般來說,在onPause
這個生命周期狀態下可以做一些數據存儲,停止動畫的工作,但是不能太耗時,,如果是由于啟動新的Activity而喚醒的該狀態,那會影響到新Activity
的顯示,原因是onPause
必須執行完,新的Activity
的onResume
才會執行。
6.onStop:與onStart
配對,表示Activity
即將停止,可以做一些稍微重量級的回收工作,同樣也不能太耗時(可以比onPause
稍微好一點)。
7.onDestroy:與onCreate配對,表示Activity即將被銷毀,這是Activity生命周期的最后一個回調,我們可以做一些回收工作和最終的資源釋放(如Service
、BroadReceiver
、Map
等)。
正常情況下,Activity
的常用生命周期就是上面的7個,下圖更加詳細的描述的各種生命周期的切換過程:
這里要說的是,從上圖我們可以看到一個現象:
onStart
與onStop
、onResume
與onPause
是配對的。兩種Activity
回到前臺的方式,從onPause
狀態回到前臺會走到onResume
狀態,從onStop
狀態回到前臺會到onStart
狀態,這是從是否可見和是否在前臺來說的。從是否可見來說,onStart
和onStop
是配對的;從是否在前臺來說,onResume
和onPause
是配對的。
我們來看看正常情況下生命周期的系統日志:
03-23 00:15:52.970 32278-32278/com.example.david.lifecircle E/TAG: onCreate() is invoked!
03-23 00:15:52.971 32278-32278/com.example.david.lifecircle E/TAG: onStart() is invoked!
03-23 00:15:52.971 32278-32278/com.example.david.lifecircle E/TAG: onResume() is invoked!
03-23 00:15:55.858 32278-32278/com.example.david.lifecircle E/TAG: onPause() is invoked!
03-23 00:16:02.573 32278-32278/com.example.david.lifecircle E/TAG: onRestart() is invoked!
03-23 00:16:02.573 32278-32278/com.example.david.lifecircle E/TAG: onStart() is invoked!
03-23 00:16:02.573 32278-32278/com.example.david.lifecircle E/TAG: onResume() is invoked!
2.異常情況下的生命周期
一般正常情況的聲明周期就像上面所說的一樣,但是因為Android本身內存或者其他的一些情況會使得Activity
不按照正常的生命周期。比如當資源配置發生改變、系統內存不足時,Activity
就會被殺死。下面分析這兩種常見的情況。
情況1:資源相關的系統配置發生改變導致Activity
被殺死并重新創建
理解這個問題,我們首先要對系統的資源加載機制有一定了解,不過這里我不分析系統資源加載機制了(因為我也不怎么懂)。簡單說明一下,就像是我們把一張圖片放在drawable
目錄之后,就可以通過Resources
去獲取這張圖片。同時為了兼容不同的設備,我們還可能需要在其他的一些目錄放置不同的圖片,比如 drawable-mdpi
、drawable-hdpi
等。這樣,當應用程序啟動時,系統就會根據當前設備的情況去加載合適的Resource
資源,比如說橫屏和豎屏的手機會拿到兩張不同的圖片(設定了landscape
或portrait
狀態下的圖片)。
如果說,當前Activity
處于豎屏狀態,如果突然旋轉屏幕,由于系統配置發生了改變,在默認情況下,Activity
就會被銷毀并重新創建(當然我們也可以組織系統重新創建,具體就在Mainfest
中申明android:Configchanges=
屬性即可)。
異常情況下的調用流程:
1.調用onSaveInstance
保存當前Activity
狀態。注意,它與onPause
方法沒有先后之分。
2.調用onStop
方法做后續處理。
3.調用onDestroy
方法銷毀當前活動。
4.重新onCreate
該活動。
5.調用onStart
方法之后,再調用onRestoreInstance
方法加載保存的數據。
6.接下來就與正常的一樣了,調用onResume
,然后運行。
我們來看一下生命周期異常運行的系統日志:
03-23 00:19:23.480 26457-26457/com.example.david.lifecircle E/TAG: onCreate() is invoked!
03-23 00:19:23.481 26457-26457/com.example.david.lifecircle E/TAG: onStart() is invoked!
03-23 00:19:23.481 26457-26457/com.example.david.lifecircle E/TAG: onResume() is invoked!
03-23 00:19:51.323 26457-26457/com.example.david.lifecircle E/TAG: onPause() is invoked!
03-23 00:19:51.324 26457-26457/com.example.david.lifecircle E/TAG: onSaveInstanceState() is invoked! Save Text = Save Data
03-23 00:19:51.478 26457-26457/com.example.david.lifecircle E/TAG: onCreate() is invoked!
03-23 00:19:51.488 26457-26457/com.example.david.lifecircle E/TAG: onStart() is invoked!
03-23 00:19:51.490 26457-26457/com.example.david.lifecircle E/TAG: onRestoreInstanceState() is invoked! Recover Text = Save Data
03-23 00:19:51.490 26457-26457/com.example.david.lifecircle E/TAG: onResume() is invoked!
情況2:資源內存不足導致低優先級的Activity
被殺死
這種情況不好模擬,但是其數據存儲和恢復過程和情況1完全一致,這里簡單的描述一下Activity
的優先級情況。Activity
的優先級從高到低可以大致分為一下三種:
(1)前臺Activity
——正在和用戶交互的Activity,優先級最高。
(2)可見但非前臺Activity
——比如Activity
中彈出了一個對話框,導致Activity
可見但無法和用戶直接交互。
(3)后臺Activity
——已經被暫停或者停止的Activity
,優先級最底。
當系統內存不足的時候,系統就會按照上述優先級從低到高來殺死目標Activity。并在后續通過onSaveInstance
和onRestoreInstance
來存儲和恢復數據。
特別提醒的是:如果一個進程中沒有四大組件(Activity
、Service
、ContentProvider
、BroadCastReceiver
)。那么這個進程就會很快被殺死,因此一些后臺工作不適合脫離四大組件而獨立運行在后臺中,否則很容易被殺死。一般是將后臺工作放入Service中從而保證進程有一定的優先級,這樣才不會被系統輕易殺死
三、生命周期的使用
1.常見的生命周期有關問題:
1.onStart
和onResume
、onPause
和onStop
從描述上看來差不多,但是他們為什么會分開呢?有什么不同?
2.兩個Activity
A
和B
,從A
中啟動B
,那么B
的onResume
與A
的onPause
哪個會先執行呢?
3.onSaveInstance
與onRestoreInstance
是任何情況下都可以使用的嘛?所有的保存數據和恢復的操作都可以在這對方法中執行?
4.如上面所說,如何使得在系統配置放生改變后,Activity
不被重新創建呢?
2.解析
1、 onStart
和onResume
、onPause
和onStop
這兩對看起來是差不多,而且很多時候都會同時調用onPause
、onStop
,然后回到onStart
、onResume
。但是在一些比較特殊的情況下就不一樣了。我們舉兩種情況,
第一種:前臺彈出了一個Dialog
,那么這個Dialog
的作用只是提醒用戶或者讓用戶輸入一個信息等就完畢了,這是一個比較輕量級的任務;
第二種:重新啟動另一個Activity
界面,轉到另一個模塊。這時新啟動的Activity
就不是一個臨時或者輕量級的任務了。
這兩種情況,第一種一般很快就會返回當前Activity
,不會太耗時;第二種可能會很久,在這段時間內系統可能需要啟動其他的應用,那么就會產生內存緊張的問題。所以,我認為是要區分這兩種情況,才會加入這兩對方法。在第一種情況下,可以在onPause
中做一些較輕微的數據存儲,因為一般很快就會回到當前Activity
;第二種情況下,適合在onStop
中做一些較重量級的存儲。除此之外,我想不到其他的使用了。
2、這個問題可以從源碼中得到解答。不過源碼太復雜,涉及底層太多(AMS
、Binder
、ActivityStack
、ActivityThread
等)。不過可以直接調用生命周期,輸出系統日志來得到解答。從下面的日志我們可以看出,的確是要等到A活動的onPause
方法之后B
才能執行(這里onCreate
沒有輸出日志):
03-23 01:02:31.339 32382-32382/com.example.david.lifecircle E/MainActivity: onCreate() is invoked!
03-23 01:02:31.341 32382-32382/com.example.david.lifecircle E/MainActivity: onStart() is invoked!
03-23 01:02:31.341 32382-32382/com.example.david.lifecircle E/MainActivity: onResume() is invoked!
03-23 01:04:04.005 32382-32382/com.example.david.lifecircle E/MainActivity: onPause() is invoked!
03-23 01:04:04.047 32382-32382/com.example.david.lifecircle E/SecondActivity: onStart() is invoked!
03-23 01:04:04.047 32382-32382/com.example.david.lifecircle E/SecondActivity: onResume() is invoked!
3、 onSaveInstance
和onRestoreInstance
是只有Activity
異常銷毀的時候才會調用的,所以這里一般執行的是Activity
異常銷毀時需要保存和恢復的數據;onSaveInstance
和onRestoreInstance
方法還可以判斷Activity
是否被重建,但正常情況下是不會調用的。所以正常情況下,還是應該在onPause
和onStop
方法中保存數據。
4、上面提到,我們可以在AndroidMainfest.xml
里,對< activity />增加一個android:configChanges屬性,來指定在哪些配置改變的情況下Activity不需要重建。如下所示:
android:configChanges="orientation|screenSize"http://界面方向以及大小的改變不需要重建
我們在AndroidMainfest.xml
做如下申明:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.david.lifecircle">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity"
android:configChanges="orientation|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SecondActivity"></activity>
</application>
</manifest>
MainActivity中的部分代碼:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.e("MainActivity","onConfigurationChanged() is invoked!"+newConfig.orientation);
}
@Override
protected void onPause() {
super.onPause();
Log.e("MainActivity","onPause() is invoked!");
}
@Override
protected void onResume() {
super.onResume();
Log.e("MainActivity","onResume() is invoked!");
}
@Override
protected void onStart() {
super.onStart();
Log.e("MainActivity","onStart() is invoked!");
}
@Override
protected void onRestart() {
super.onRestart();
Log.e("MainActivity","onRestart() is invoked!");
}
點擊屏幕旋轉,然后來看一下系統日志輸出:
03-23 01:14:11.357 10361-10361/com.example.david.lifecircle E/MainActivity: onCreate() is invoked!
03-23 01:14:11.359 10361-10361/com.example.david.lifecircle E/MainActivity: onStart() is invoked!
03-23 01:14:11.359 10361-10361/com.example.david.lifecircle E/MainActivity: onResume() is invoked!
03-23 01:14:28.140 10361-10361/com.example.david.lifecircle E/MainActivity: onConfigurationChanged() is invoked!2
03-23 01:14:38.294 10361-10361/com.example.david.lifecircle E/MainActivity: onConfigurationChanged() is invoked!1
03-23 01:14:47.531 10361-10361/com.example.david.lifecircle E/MainActivity: onConfigurationChan
我們發現,屏幕旋轉之后,并沒有重新調用生命周期,說明活動并沒有被重建。configChanges屬性還有許多的值,如:mcc\mnc\local\touchscreen\keyboard等等。
最后用一個實際的例子來說明Activity的各個生命周期。假設有一個程序由2個Activity`` A
和B
組成,A
是這個程序的啟動界面。當用戶啟動程序時,Process
和默認的Task分別被創建,接著A被壓入到當前的Task
中,依次執行了 onCreate
, onStart
, onResume
事件被呈現給了用戶;此時用戶選擇A
中的某個功能開啟界面B
,界面B
被壓入當前Task
遮蓋住了A
,A
的onPause
事件執行,B
的 onCreate
, onStart
, onResume
事件執行,呈現了界面B
給用戶;用戶在界面B
操作完成后,使用Back
鍵回到界面A
,界面B
不再可見,界面B
的onPause
, onStop
, onDestroy
執行,A
的onResume
事件被執行,呈現界面A
給用戶。此時突然來電,界面A
的onPause
事件被執行,電話接聽界面被呈現給用 戶,用戶接聽完電話后,又按了Home
鍵回到桌面,打開另一個程序“聯系人”,添加了聯系人信息又做了一些其他的操作,此時界面A
不再可見,其 onStop
事件被執行,但并沒有被銷毀。此后用戶重新從菜單中點擊了我們的程序,由于A
和其所在的進程和Task
并沒有被銷毀,A
的onRestart
和onStart
事件被執行,接著A
的onResume
事件被執行,A
又被呈現給了用戶。用戶這次使用完后,按Back
鍵返回到桌面,A
的 onPause
, onStop
被執行,隨后A
的onDestroy
被執行,由于當前Task
中已經沒有任何Activity
,A
所在的Process
的重要程度被降到很 低,很快A
所在的Process
被系統結束
常見的例子
情形一、一個單獨的Activity
的正常的生命過程是這樣的:onCreate
->onStart
->onPause
->onStop
->onDestroy
。例如:運行一個Activit
,進行了一些簡單操作(不涉及頁面的跳轉等),然后按返回鍵結束。
情形二、有兩個Activity
(a和b),一開始顯示a,然后由a啟動b,然后在由b回到a,這時候a的生命過程應該是怎么樣的呢(a被b完全遮蓋)?
a經歷的過程為onCreate
->onStart
->onResume
->onPause
->onStop
->onRestart
->onStart
->onResume
。這個過程說明了圖中,如果Activity
完全被其他界面遮擋時,進入后臺,并沒有完全銷毀,而是停留在onStop
狀態,當再次進入a時,onRestart
->onStart
->onResume
,又重新恢復。
情形三、基本情形同二一樣,不過此時a被b部分遮蓋(比如給b添加個對話框主題 android:theme=”@android:style/Theme.Dialog”)
a經歷的過程是:onCreate
->onStart
->onResume
->onPause
->onResum
e
所以當Activity
被部分遮擋時,Activity進入onPause
,并沒有進入onStop
,從Activity2
返回后,執行了onResume
情形四、 打開程序,啟動a,點擊a,啟動AlertDialog
,按返回鍵從AlertDialog返回。
a經歷的過程是:onCreate
->onStart
->onResume
當啟動和退出Dialog
時,Activity
的狀態始終未變,,因為Dialog
實際上時一個View
,它是屬于某一個Activity
的,因此如果Dialog
顯示在當前Activity
之前時不會影響到Activity
的生命周期的。但是如果是其他Activity
的Dialog
彈出那么就會觸發onPause()
方法的執行。
摘自 https://blog.csdn.net/woshimalingyi/article/details/50961380