先發一張安卓官方文檔裏面的Activity生命週期圖解前端
下面在對這7個生命週期內相關的方法作一些簡單的介紹java
當Activity被建立的時候,會自動運行該方法。該方法作一些初始化動做,該方法提供了一個Bundle類型的變量,這個變量中有這個Activity之前的狀態信息,前提是之前存過這些信息。這個方法執行完以後執行的是OnStart()方法;若在OnCreate()方法中調用finish()方法,OnCreate()方法執行完以後直接調用OnDestroy()方法。android
通常在裏面設置所使用的佈局文件,而且進行一些靜態的的操做。app
把一個Activity從OnStop狀態喚醒時,會調用OnRestart()方法,這個方法優先於再次運行的OnStart(),執行完OnRestart()以後再執行OnStart()。若在OnRestart()方法中加入finish()方法,則仍是會繼續執行OnStart()及後面的狀態方法直到OnDestroy()運行完。ide
當一個Activity對用戶可見時會調用OnStart(),當Activity在前臺運行時(得到輸入焦點),會調用OnResume();佈局
當Activity還沒在前臺運行就被隱藏了會運行OnStop(),好比在OnStart()方法中用finish()方法的話,OnStart()以後就會直接運行OnStop()→OnDestroy()。測試
當Activity開始與用戶交互時(得到用戶焦點),會調用OnResume(),而且爲了用戶操做,此時該Activity位於Activity棧的頂部。通過某些操做後該方法執行完以後執行的是OnPause()。動畫
當一個Activity運行到OnResume()方法以後,不論是這個Activity要銷燬仍是要暫停或者中止,都會調用該方法。這個方法以後多是OnResume()或者OnStop()。this
應用程序啓動了另一個Activity時候,第一個Activity也會調用OnPause()。例如:在操做時,來了一個電話,會調用前一個Activity的OnPause()方法,作一些保存工做,便於恢復。3d
如果在這個Activity-A中打開一個不徹底覆蓋這個Activity-A的新的Activity-B,那麼Activity-A就會是OnPause()狀態,當Activity-B退出時,Activity-A就會執行OnResume()方法。如果須要退出Activity-A,那麼下一個就會執行OnStop()。OnPause()用於提交未保存發生變化了的持久化數據,及中止動畫及其餘比較消耗CPU的事件或者消耗電量的資源,這是爲了更好的運行新的Activity。
當這個Activity【徹底】看不見的時候,會調用OnStop()方法,由於另外一個Activity會調用OnResume()而且覆蓋這個Activity。如下三種狀況會使這個Activity調用OnStop()方法:
1.新的Activity被執行
2.一個已經存在的Activity被切換到最前端
3.這個Activity要被銷燬
若是經過用戶召回這個Activity,那麼會調用OnRestart()方法,若這個Activity要被銷燬,則調用OnDestroy()方法。
當Activity銷燬前會調用該方法,好比發生以下狀況:
1.Activity調用finish()方法來結束這個Activity
2.或者由於系統爲了節省空間而臨時銷燬這個Activity
這兩種狀況能夠經過isFinishing()方法判斷
1.啓動Activity:系統會先調用onCreate()方法,而後調用onStart()方法,最後調用onResume(),Activity進入運行狀態。
2.當前Activity被其餘Activity覆蓋或被鎖屏:系統會調用onPause()方法,暫停當前Activity的執行。
3.當前Activity由被覆蓋狀態回到前臺或解鎖屏:系統會調用onResume()方法,再次進入運行狀態。
4.當前Activity轉到新的Activity界面或按Home鍵回到主屏,自身退居後臺:系統會先調用onPause()方法,而後再調用onStop()方法,進入停滯狀態。
5.用戶後退回到此Activity:系統會先調用onRestart()方法,而後調用onStart()方法,最後調用onResume()方法,再次進入運行狀態。
6.當前Activity處於被覆蓋狀態或者後臺不可見狀態,即第2步或第4步,系統內存不足,殺死當前Activity,然後用戶退回當前Activity:再次調用onCreate()、onStart()、onResume(),進入運行狀態。
7.用戶退出當前Activity:系統會調用onPause()方法,而後調用onStop()方法,最後調用onDestory()方法,結束當前Activity。
可是知道這些還不夠,咱們必須親自試驗一下才能深入體會,融會貫通。
下面咱們就結合實例,來演示一下生命週期的幾個過程的詳細狀況。咱們新建一個名爲lifecycle的項目,建立一個名爲LifeCycleActivity的Activity,以下:
package com.pingge.lifecycle; import java.lang.annotation.Target; import android.os.Bundle; import android.R.integer; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.util.Log; import android.view.Menu; import android.view.View; import android.widget.Button; public class LifeCycleActivity extends Activity { private static final String TAG = "LifeCycleActivity"; private Context context = this; private int param = 1; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Activity建立時被調用 super.onCreate(savedInstanceState); Log.i(TAG, "onCreate() called"); setContentView(R.layout.activity_life_cycle); Button btn = (Button)findViewById(R.id.btn); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub Intent intent = new Intent(context, OrientationActivity.class); startActivity(intent); } }); } @Override protected void onDestroy() { // TODO 退出當前Activity時被調用,調用以後Activity就結束了 super.onDestroy(); Log.i(TAG, "onDestory() called"); } @Override protected void onPause() { // TODO Activity被覆蓋或者鎖屏時被調用 super.onPause(); Log.i(TAG, "onPause() called"); } @Override protected void onRestart() { // TODO Activity從後臺從新回到前臺時被調用 super.onRestart(); Log.i(TAG, "onRestart() called"); } @Override protected void onResume() { // TODO Activity建立或者從被覆蓋、後臺從新回到前臺時被調用 super.onResume(); Log.i(TAG, "onResume() called"); } @Override protected void onStart() { // TODO Activity建立或者從後臺從新回到前臺時被調用 super.onStart(); Log.i(TAG, "onStart() called"); } @Override protected void onStop() { // TODO 退出當前Activity或者跳轉到新的Activity時被調用 super.onStop(); Log.i(TAG, "onStop() called"); } /* * Activity被系統殺死以後再從新建立時被調用 * 例如:屏幕方向改變時,Activity被銷燬再重建; * 當前Activity處於後臺,系統資源緊張將其殺死,用戶又啓動了該Activity * 這兩種狀況下onRestoreInstanceState()都會被調用,在onStart()以後 * * @see android.app.Activity#onRestoreInstanceState(android.os.Bundle) */ @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onRestoreInstanceState(savedInstanceState); param = savedInstanceState.getInt("param"); Log.i(TAG, "onRestoreInstanceState() called : " + param); } /* * Activity被系統殺死時被調用 * 例如:屏幕方向改變時,Activity被銷燬再重建; * 當前Activity處於後臺,系統資源緊張將其殺死 * 另外,當跳轉到其餘Activity或者按HOME鍵回到主屏時該方法也會被調用 * 系統是爲了保存當前View組件的狀態 * 在onPause()方法以後被調用 * * @see android.app.Activity#onSaveInstanceState(android.os.Bundle) */ @Override protected void onSaveInstanceState(Bundle outState) { // TODO Auto-generated method stub super.onSaveInstanceState(outState); outState.putInt("param", param + 1); Log.i(TAG, "onSaveInstanceState() called : " + param); } @Override public void onWindowFocusChanged(boolean hasFocus) { // TODO 當Activity窗口得到或失去焦點時被調用,在onResume()以後或onPause()以後 super.onWindowFocusChanged(hasFocus); Log.i(TAG, "onWindowFocusChanged() called"); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.life_cycle, menu); return true; } }
你們注意到,除了幾個常見的方法外,咱們還添加了
onWindowFocusChanged、onSaveInstanceState、onRestoreInstanceState這三個方法。
1. onWindowFocusChanged
在Activity窗口得到或失去焦點時被調用,例如:建立時首次呈如今用戶面前;當前Activity被其餘Activity覆蓋;當前Activity轉到其餘Activity或按HOME鍵回到主屏,自身退居後臺;用戶退出當前Activity。以上幾種狀況都會調用onWindowFocusChanged,而且當Activity被建立時是在OnResume以後被調用,當Activity被覆蓋或者退居後臺或者當前Activity退出時,它是在onPause()以後被調用,以下圖所示:
這個方法在某種場合下仍是頗有用的,例如:程序啓動時想要獲取特定視圖組件的尺寸大小,在onCreate中可能沒法取到,由於窗口window對象還沒建立完成,這個時候咱們就須要在onWindowFocusChanged裏獲取。
2. onSaveInstanceState
(1)在Activity被覆蓋或退居後臺以後,系統資源不足將其殺死,此方法會被調用。
(2)在用戶改變屏幕方向時,此方法會被調用。
(3)在當前Activity跳轉到其餘Activity或者按HOME鍵回到主屏,自身退居後臺時,此方法被調用。
第一種狀況咱們沒法保證何時發生,系統根據資源緊張程度去調度;
第二種是屏幕翻轉方向時,系統先銷燬當前的Activity,而後再重建一個新的,調用此方法時,咱們能夠保存一些臨時的數據;
第三種狀況系統調用此方法是爲了保存當前窗口各個View組件的狀態。onSaveInstanceState的調用順序是在onPause以後。
下圖是按Back鍵後的調用順序:
3. onRestoreInstanceState
(1)在Activity被覆蓋或退居後臺以後,系統資源不足將其殺死,而後用戶又回到了此Activity,此方法會被調用。
(2)在用戶改變屏幕方向時,重建的過程當中,此方法會被調用。
咱們能夠重寫此方法,以即可以恢復一些臨時數據。onRestoreInstanceState的調用順序是在onStart以後。
下圖是改變屏幕方向時的調用順序:
以上着重介紹了三個相對陌生的方法以後,下面咱們就來操做一下這個Activity,看看它的生命週期究竟是個什麼樣的過程。
在系統調用了onCreate和onStart以後,調用了onResume,自此,Activity進入了運行狀態。
咱們看到,此時onSaveInstanceState方法在onPause以後被調用了。
從後臺回到前臺時,系統會先調用onRestart方法,而後調用onStart方法,最後調用onResume方法,Activity又進入了運行狀態。
咱們注意到,此時LifeCycleActivity的onPause方法被調用,並無調用onStop方法,由於此時TargetActivity沒有徹底覆蓋掉LifeCycleActivity,LifeCycleActivity仍是有一部分處於可見狀態。
此時只有onResume方法被調用,直接再次進入運行狀態。
最後的onDestory方法被調用,標誌着LifeCycleActivity的終結。
你們彷佛注意到,在全部的過程當中,並無onRestoreInstanceState的出現,這個並不奇怪,由於以前咱們就說過,onRestoreInstanceState只有在
(1)殺死不在前臺的Activity以後用戶回到此Activity
(2)用戶改變屏幕方向的這兩個重建過程當中被調用。
咱們要演示第一種狀況比較困難,咱們能夠結合第二種狀況演示一下具體的過程。順便也向你們講解一下屏幕方向改變的應對策略。
咱們能夠爲一個Activity指定一個特定的方向,指定以後即便轉到屏幕方向,顯示方向也不會跟着改變:
在AndroidManifest.xml中對指定的Activity設置: android:screenOrientation="portrait"
或者在onCreate方法中指定:setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
在AndroidManifest.xml中對指定的Activity設置: android:screenOrientation="landscape"
或者在onCreate方法中指定:setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
爲應用中的Activity設置特定的方向是常常用到的辦法,能夠爲咱們省去很多沒必要要的麻煩。不過,咱們今天講的是屏幕方向改變時的生命週期,因此咱們並不採用固定屏幕方向這種辦法。
下面咱們就結合實例講解一下屏幕轉換的生命週期,咱們新建一個Activity命名爲OrientationActivity,以下:
package com.pingge.lifecycle; import android.app.Activity; import android.content.res.Configuration; import android.os.Bundle; import android.util.Log; public class OrientationActivity extends Activity { private static final String TAG = "OrientationActivity"; private int param = 1; /* * 當指定了android:configChanges="orientation"後, * 方向改變時,onConfigurationChanged被調用 * @see android.app.Activity#onConfigurationChanged(android.content.res.Configuration) */ @Override public void onConfigurationChanged(Configuration newConfig) { // TODO Auto-generated method stub super.onConfigurationChanged(newConfig); switch (newConfig.orientation) { case Configuration.ORIENTATION_PORTRAIT: Log.i(TAG, "onConfigurationChanged() called" + "PORTRAIT"); break; case Configuration.ORIENTATION_LANDSCAPE: Log.i(TAG, "onConfigurationChanged() called" + "LANDSCAPE"); break; default: Log.i(TAG, "onConfigurationChanged() called" + "DEFAULT"); break; } } @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.activity_orientation); Log.i(TAG, "onCreate() called"); } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); Log.i(TAG, "onDestory() called"); } @Override protected void onPause() { // TODO Auto-generated method stub super.onPause(); Log.i(TAG, "onPause() called"); } @Override protected void onRestart() { // TODO Auto-generated method stub super.onRestart(); Log.i(TAG, "onRestart() called"); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onRestoreInstanceState(savedInstanceState); param = savedInstanceState.getInt("param"); Log.i(TAG, "onRestoreInstanceState() called : " + param); } @Override protected void onResume() { // TODO Auto-generated method stub super.onResume(); Log.i(TAG, "onResume() called"); } @Override protected void onSaveInstanceState(Bundle outState) { // TODO Auto-generated method stub super.onSaveInstanceState(outState); outState.putInt("param", param); Log.i(TAG, "onSaveInstanceState() called : " + param); } @Override protected void onStart() { // TODO Auto-generated method stub super.onStart(); Log.i(TAG, "onStart() called"); } @Override protected void onStop() { // TODO Auto-generated method stub super.onStop(); Log.i(TAG, "onStop() called"); } }
首先咱們必須打開手機的"自動旋轉開關",代表能夠自動根據方向旋轉屏幕,而後咱們就能夠測試流程了,當咱們旋轉屏幕時,咱們發現系統會先將當前Activity銷燬,而後重建一個新的:
系統先是調用onPause方法暫停當前Activity,而後調用onSaveInstanceState方法,咱們保存了一個臨時參數到Bundle對象裏面,而後當Activity重建以後咱們又成功的取出了這個參數。
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.pingge.lifecycle" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="18" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.pingge.lifecycle.LifeCycleActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="com.pingge.lifecycle.TargetActivity" > </activity> <activity android:name="com.pingge.lifecycle.OrientationActivity" android:configChanges="orientation|screenSize" > </activity> </application> </manifest>
爲了不這樣的銷燬重建的過程,咱們須要在AndroidManifest.xml中對OrientationActivity對應的<activity>配置android:configChanges="orientation|screenSize",而後咱們再測試一下,咱們試着作了四次旋轉,打印以下:
能夠看到,每次旋轉方向時,只有onConfigurationChanged方法被調用,沒有了銷燬重建的過程。
注意:
若是<activity>配置了android:screenOrientation屬性,則會使android:configChanges="orientation"失效。
當用戶本身退出程序的時候,建議在OnStop()方法中保存數據;
當用戶打開一個新的Activity的時候,建議經過OnSaveInstanceState()來保存數據;這裏在網上看到不少人說應該方法OnPause()裏保存,其實我以爲在打開新的一個Activity的時候,或者將程序至於後臺的時候,都會默認調用OnSaveInstanceState()方法,並且在這種暫停的狀態下,Android的內存管理機制也不太會殺死這種狀態的Activity。而用OnPause()保存的時候,如果下一個執行OnResume()方法的話,會影響速度,固然數據量小的話也感受不到。