Activity是由Activity棧進管理,當來到一個新的Activity後,此Activity將被加入到Activity棧頂,以前的Activity位於此Activity底部。Acitivity通常意義上有四種狀態:java
1.當Activity位於棧頂時,此時正好處於屏幕最前方,此時處於運行狀態;瀏覽器
2.當Activity失去了焦點但仍然對用於可見(如棧頂的Activity是透明的或者棧頂Activity並非鋪滿整個手機屏幕),此時處於暫停狀態;網絡
3.當Activity被其餘Activity徹底遮擋,此時此Activity對用戶不可見,此時處於中止狀態;ide
4.當Activity因爲人爲或系統緣由(如低內存等)被銷燬,此時處於銷燬狀態;函數
在每一個不一樣的狀態階段,Adnroid系統對Activity內相應的方法進行了回調。所以,咱們在程序中寫Activity時,通常都是繼承Activity類並重寫相應的回調方法。this
在上圖中,Activity有三個關鍵的循環: spa
1.Activity實例是由系統自動建立,並在不一樣的狀態期間回調相應的方法。Activity在onCreate()設置全部的「全局」狀態,在onDestory()釋放全部的資源。一個最簡單的完整的Activity生命週期會按照以下順序回調:onCreate -> onStart -> onResume -> onPause -> onStop -> onDestroy。稱之爲entire lifetime(整個的生命週期)。例如:某個Activity有一個在後臺運行的線程,用於從網絡下載數據,則該Activity能夠在onCreate()中建立線程,在onDestory()中中止線程。線程
2.當執行onStart回調方法時,Activity開始被用戶所見(也就是說,onCreate時用戶是看不到此Activity的,那用戶看到的是哪一個?固然是此Activity以前的那個Activity),一直到onStop以前,此階段Activity都是被用戶可見,稱之爲visible lifetime(可見的生命週期)。儘管有可能不在前臺,不能和用戶交互。在這兩個接口之間,須要保持顯示給用戶的UI數據和資源等,例如:能夠在onStart中註冊一個IntentReceiver來監聽數據變化致使UI的變更,當再也不須要顯示時候,能夠在onStop()中註銷它。onStart(),onStop()均可以被屢次調用,由於Activity隨時能夠在可見和隱藏之間轉換。code
3.當執行到onResume回調方法時,Activity能夠響應用戶交互,一直到onPause方法以前,該Activity處於全部 Activity的最前面,和用戶進行交互。此階段Activity稱之爲foreground lifetime(前臺的生命週期)。Activity能夠常常性地在resumed和paused狀態之間切換,例如:當設備準備休眠時,當一個 Activity處理結果被分發時,當一個新的Intent被分發時。因此在這些接口方法中的代碼應該屬於很是輕量級的。orm
須要注意一下幾點:
在實際應用場景中,假設A Activity位於棧頂,此時用戶操做,從A Activity跳轉到B Activity。那麼對AB來講,具體會回調哪些生命週期中的方法呢?回調方法的具體回調順序又是怎麼樣的呢?
開始時,A被實例化,執行的回調有A:onCreate -> A:onStart -> A:onResume。
當用戶點擊A中按鈕來到B時,假設B所有遮擋住了A,將依次執行A:onPause -> B:onCreate -> B:onStart -> B:onResume -> A:onStop。
此時若是點擊Back鍵,將依次執行B:onPause -> A:onRestart -> A:onStart -> A:onResume -> B:onStop -> B:onDestroy。
至此,Activity棧中只有A。在Android中,有兩個按鍵在影響Activity生命週期這塊須要格外區分下,即Back鍵和Home鍵。咱們先直接看下實驗結果:
此時若是按下Back鍵,系統返回到桌面,並依次執行A:onPause -> A:onStop -> A:onDestroy。
此時若是按下Home鍵(非長按),系統返回到桌面,並依次執行A:onPause -> A:onStop。因而可知,Back鍵和Home鍵主要區別在因而否會執行onDestroy。
此時若是長按Home鍵,不一樣手機可能彈出不一樣內容,Activity生命週期未發生變化(由小米2s測的,不知道其餘手機是否會對Activity生命週期有影響)。
因爲Android自己的特性,使得如今很多應用都沒有直接退出應用程序的功能,按照通常的邏輯,當Activity棧中有且只有一個Activity時,當按下Back鍵此Activity會執行onDestroy,那麼下次點擊此應用程圖標將從從新啓動,所以,當前很多應用程序都是採起如Home鍵的效果,當點擊了Back鍵,系統返回到桌面,而後點擊應用程序圖標,直接回到以前的Activity界面,這種效果是怎麼實現的呢?
經過重寫按下Back鍵的回調函數,轉成Home鍵的效果便可。
@Override public void onBackPressed() { Intent home = new Intent(Intent.ACTION_MAIN); home.addCategory(Intent.CATEGORY_HOME); startActivity(home); }
固然,此種方式經過Home鍵效果強行影響到Back鍵對Activity生命週期的影響。注意,此方法只是針對按Back鍵須要退回到桌面時的Activity且達到Home效果才重寫。
或者,爲達到此類效果,Activity實際上提供了直接的方法。
activity.moveTaskToBack(true);
moveTaskToBack()此方法直接將當前Activity所在的Task移到後臺,同時保留activity順序和狀態。
在以前的項目開發過程當中,當時遇到一個很奇怪的問題:手機上的「開發者選項」中有一個「不保留活動」的設置,當開啓此設置,手機上的設置提示是「用戶離開後即銷燬每一個活動」,開啓後,對於其餘的應用程序是從A Acticity到B Activity,而後Back鍵回到A,此時,其餘應用程序只是先白屏(有可能黑屏等,取決於主題設置)一下,而後A開始可見,可是個人應用程序中出現的一個結果倒是直接返回到了桌面。一開始百思不得其解。最後終於定位出問題。首先,咱們須要明確開啓此設置項後對Activity生命週期的影響。開啓此設置項後,當A到B時,假設B所有遮擋住了A,將依次執行A:onPause -> B:onCreate -> B:onStart -> B:onResume -> A:onStop -> A:onDestroy。是的,A在系統本來的生命週期回調中增長了onDestroy。此即「用戶離開後即銷燬每一個活動」的含義。但此時須要注意的是,只要沒有認爲的調用A的finish()方法,雖然A執行了onDestroy,但Activity棧中依然保留有A,此時B處於棧頂。那麼在B中按Back鍵回到A時,將依次執行:B:onPause -> A:onCreate -> A:onStart -> A:onResume -> B:onStop -> B:onDestroy。沒錯,A從onCreate開始執行了。此處也就解釋了爲何A可能會出現白屏(或黑屏等)一下的緣由了。
那麼爲何個人應用程序會跟其餘應用程序出現不同呢?最後定爲出問題在於當時個人應用程序中爲了作到徹底退出應用程序效果,專門使用了一個Activity棧去維護Activity(當時是借鑑了網上的此類實現方案,如今想一想,實在不必,且不說Android自己特性決定了不必經過如此方法去達到退出效果,僅僅是此方法自己也存在很大的問題,如今在網上依然能見到有很多文章說到應用程序退出可使用此方法,哎。。),在onCreate中入棧,onDestroy出棧,調用了以下方法:
// 結束Activity&從堆棧中移除 AppManager.getAppManager().finishActivity(this);
其中,AppManager中finishActivity函數具體定義是:
/** * 結束指定的Activity */ public void finishActivity(Activity activity) { if (activity != null) { activityStack.remove(activity); activity.finish(); activity = null; } }
至此,相信你們應該看出問題的所在了吧。
沒錯,問題在於執行了activity的finish()方法!! activity的finish()方法至少有兩個層面含義,1.將此Activity從Activity棧中移除,2.調用了此Activity的onDestroy方法。對於不開啓「不保留活動」的設置項,實際上也沒什麼影響,可是一旦開啓此設置,問題顯露無疑。開啓此此設置後,正常狀況下離開A,即便執行了A的onDestroy,Activity棧中仍是有A的,可是我這樣寫後,finish()方法一執行,Activity棧中就沒有A了,所以,當點擊Back鍵時,Activity棧中已經沒有此應用的任何Activity了,直接來到了手機桌面。
可能,有些人會說,我就是要經過此種方法想去徹底退出應用程序,同時但願本身的Activity棧和系統中Activity棧保持一致,怎麼辦呢?
在此,能夠經過以下改寫去實現:
/** * 結束指定的Activity */ public void finishActivity(Activity activity) { if (activity != null) { // 爲與系統Activity棧保持一致,且考慮到手機設置項裏的"不保留活動"選項引發的Activity生命週期調用onDestroy()方法所帶來的問題,此處須要做出以下修正 if(activity.isFinishing()){ activityStack.remove(activity); //activity.finish(); activity = null; } } }
下面經過一個例子來介紹:
public class ActivityDemo extends Activity { private static final String TAG = "ActivityDemo"; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Log.e(TAG, "start onCreate~~~"); } @Override protected void onStart() { super.onStart(); Log.e(TAG, "start onStart~~~"); } @Override protected void onRestart() { super.onRestart(); Log.e(TAG, "start onRestart~~~"); } @Override protected void onResume() { super.onResume(); Log.e(TAG, "start onResume~~~"); } @Override protected void onPause() { super.onPause(); Log.e(TAG, "start onPause~~~"); } @Override protected void onStop() { super.onStop(); Log.e(TAG, "start onStop~~~"); } @Override protected void onDestroy() { super.onDestroy(); Log.e(TAG, "start onDestroy~~~"); } }
咱們打開應用時前後執行了onCreate()->onStart()->onResume()三個方法,看一下LogCat視窗以下:
當咱們按BACK鍵時,咱們這個應用程序將結束,這時候咱們將前後調用onPause()->onStop()->onDestory()三個方法,以下圖所示:
當咱們打開應用程序時,好比瀏覽器,我正在瀏覽NBA新聞,看到一半時,我忽然想聽歌,這時候咱們會選擇按HOME鍵,而後去打開音樂應用程序,而當咱們按HOME的時候,Activity前後執行了onPause()->onStop()這兩個方法,這時候應用程序並無銷燬。以下圖所示:
而當咱們再次啓動ActivityDemo應用程序時,則前後分別執行了onRestart()->onStart()->onResume()三個方法,以下圖所示:
這裏咱們會引出一個問題,當咱們按HOME鍵,而後再進入ActivityDemo應用時,咱們的應用的狀態應該是和按HOME鍵以前的狀態是同樣的,一樣爲了方便理解,在這裏我將ActivityDemo的代碼做一些修改,就是增長一個EditText。而後再次運行ActivityDemo程序,在EditText裏輸入如"Frankie"字符串(以下圖:)
這時候,你們能夠按一下HOME鍵,而後再次啓動ActivityDemo應用程序,這時候EditText裏並無咱們輸入的"Frankie"字樣,以下圖:
這顯然不能稱得一個合格的應用程序,因此咱們須要在Activity幾個方法裏本身實現,修改ActivityDemo.java代碼以下:
public class ActivityDemo extends Activity { private static final String TAG = "ActivityDemo"; private EditText mEditText; //定義一個String 類型用來存取咱們EditText輸入的值 private String mString; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mEditText = (EditText)findViewById(R.id.editText); Log.e(TAG, "start onCreate~~~"); } @Override protected void onStart() { super.onStart(); Log.e(TAG, "start onStart~~~"); } //當按HOME鍵時,而後再次啓動應用時,咱們要恢復先前狀態 @Override protected void onRestart() { super.onRestart(); mEditText.setText(mString); Log.e(TAG, "start onRestart~~~"); } @Override protected void onResume() { super.onResume(); Log.e(TAG, "start onResume~~~"); } //當咱們按HOME鍵時,我在onPause方法裏,將輸入的值賦給mString @Override protected void onPause() { super.onPause(); mString = mEditText.getText().toString(); Log.e(TAG, "start onPause~~~"); } @Override protected void onStop() { super.onStop(); Log.e(TAG, "start onStop~~~"); } @Override protected void onDestroy() { super.onDestroy(); Log.e(TAG, "start onDestroy~~~"); } }
從新運行ActivityDemo程序,重複第五步操做,當咱們按HOME鍵時,再次啓動應用程序時,EditText裏有上次輸入的"Frankie"字樣,以下圖如示:
OK,大功基本告成,這時候你們能夠在回上面看一下Activity生命週期圖,我想你們應該徹底瞭解了Activity的生命週期了,不知道你瞭解了沒?
最後再用一個實際的例子來講明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產生事件彈出Toast和AlertDialog的時候Activity的生命週期是不會有改變,即不會觸發onPause()等事件。