首先,Activity是Android系統中的四大元件之一,可以用于顯示View。Activity是一個與用記互動的系統子產品,幾乎所有的 Activity都是和使用者進行互動的,但是如果這樣就能說Activity主要是用來顯示View就不太正确了。它不僅顯示資料,也傳輸資料,很多程式中使用到MVC模式,
M(Model 模型):Model是應用程式的主體部分,所有的業務邏輯都應該寫在這裡,在Android中Model層與JavaEE中的變化不大,如:對資料庫的操 作,對網絡等的操作都放在該層(但不是說它們都放在同一個包中,可以分開放,但它們統稱為Model層)。
V(View 視圖):是應用程式中負責生成使用者界面的部分,也是在整個MVC架構中使用者唯一可以看到的一層,接收使用者輸入,顯示處理結果;在Android應用中一般 采用XML檔案裡德界面的描述,使用的時候可以非常友善的引入,當然也可以使用JavaScript+Html等方式作為View。
C(Controller控制層)android的控制層的重任就要落在衆多的activity的肩上了,是以在這裡就要建議大家不要在activity中寫太多的代碼,盡量能過activity交割Model業務邏輯層處理。
在Android中Activity主要是用來做控制的,它可以選擇要 顯示的View,也可以從View中擷取資料然後把資料傳給Model層進行處理,最後再來顯示出處理結果。
也有一種新的MVP模式:
模型(Model):負責處理資料的加載或者存儲,比如從網絡或本地資料庫擷取資料等;
視圖(View):負責界面資料的展示,與使用者進行互動;
主持人(Presenter):相當于協調者,是模型與視圖之間的橋梁,将模型與視圖分離開來。
其中的主要内容這裡不介紹,這裡告訴大家,不僅僅需要學習MVC模式,也需要學習MVP模式,這裡特别不建議大家這樣寫:将所有的事情都交給Activity來完成,比如網絡請求,業務邏輯處理,這樣造成了Activity特别臃腫,一個大的Activity,在後期很難維護。MVC如果用不好,就會将所有的資訊都放在Activity上。
protected void onCreate(Bundle icicle);
protected void onStart();
protected void onRestart();
protected void onResume();
protected void onPause();
protected void onStop();
protected void onDestroy();
要想了解Activity,那麼就必須要清楚Activity的生命周期,圖檔是最生動的,如下圖:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiIXZ05WZD9CX5RXa2Fmcn9CXwczLcVmds92czlGZvwVP9EUTDZ0aRJkSwk0LcxGbpZ2LcBDM08CXlpXazRnbvZ2LcRlMMVDT2EWNvwFdu9mZvwVPrNTY2AHWlZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39DM3IzNxgzM5EDOyMDM1EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
上面一張圖有可能有些模糊,那請看下面這張圖():
整個Activity周期,activity建立時調用Oncreate(),這個時候調用setContentView(View)函數,加載xml布局檔案。調用OnStart()方法,Activity顯示在螢幕上,這個時候還不能與使用者互動,調用OnResume()方法,使用者與Activity進行互動,目前Activity被切換的時候,這個時候調用OnPause()方法,在該方法中儲存一些持久資料和釋放占用的資源,這個時候,螢幕還是可見,調用onStop()方法,Activity切換到背景,使用者不可見。onDestroy()activity終止。
Activity的響應時間
目前Activity所在的線程為主線程,它的響應時間為5秒,如果在目前運作的Activity中進行耗時的操作且響應時間起過5秒,那麼程式就會報ANR錯誤。是以,這也是不建議在Activity中寫太多複雜代碼的原因之一。
當然,有些代碼隻能寫在Activity中,不然就運作不了(它們不是生命周期方法),比如你想要獲得android系統或者硬體一的些資訊,就必須在Activity中寫出來,如果單獨寫一個工具類獲得不了。
Activity棧
Activity棧儲存了已經啟動并且還沒有終止的所有的Activity,并且我們知道棧是遵從“後進先出”的規則,那麼Activity棧同樣也遵從這樣的規則。
Activity 的狀态與其在Activity棧的位置有着密切的關系。不僅如此,Android系統在資源不足時,也是通過Activity棧來選擇哪些 Activity是可以被終止的,一般來講,Activity系統會優先選擇終止處于目前是停止狀态并且比較靠近Activity棧底的 Activity。
1. Activity的4種狀态
Activity的生命周期指Activity從啟動到銷毀的過程,Activity有4種狀态:
(1)活動(Active)狀态:這時候Activity處于棧頂,且是可見的,有焦點的,能夠接收使用者輸入前 景Activity。Runtime将試圖不惜一切代價保持它活着,甚至殺死其他Activity以確定它有它所需的資源。當另一個Activity變成Active時,目前 的将變成Paused狀态。
(2)暫停(Paused)狀态:在 某些情況下,你的Activity是可見的,但沒有焦 點,在這時候,Actvity處于Paused狀态。例如,如果有一個透明或非全螢幕上的Activity在你的Actvity上面,你的 Activity将。當處于Paused狀态時,該Actvity仍被認為是Active的,但是它不接受使用者輸入事件。在極端情況下,Runtime将 殺死Paused Activity,以進一步回收資源。當一個Actvity完全被遮住時,它将進入Stopped狀态。
(3)停止(Stopped)狀态:當Activity是不可見的時,Activity處于Stopped狀态。Activity将繼續保留在記憶體中保持目前的所有狀态和成員資訊,假 設系統别的地方需要記憶體的話,這時它是被回收對象的主要候選。當Activity處于Stopped狀态時,一定要儲存目前資料和目前的UI狀态,否則一 旦Activity退出或關閉時,目前的資料和UI狀态就丢失了。
(4)非活動(Inactive)狀态:Activity被殺掉以後或者被啟動以前,處于Inactive狀态。這時Activity已被移除從Activity堆棧中,需要重新啟動才可以顯示和使用。
一些調用執行個體
1) 啟動Activity:onCreate()->onStart()->onResume()->Activityis running
2) 按back鍵傳回:onPause()->onStop()->onDestroy() 再次啟動時:onCreate()->onStart()->onResume()->Activityis running
3). 按home鍵傳回:onPause()->onStop() 再次啟動時:onRestart()->onStart()->onResume()->Activity isrunning
4) 切換到别的Activity(目前Activity不finish),或者采用這個,啟動程式進入Activity,按Home鍵進入桌面,然後長按Home建點選該應用重新進入Activity:onPause()->onStop() 再次啟動時:onRestart()->onStart()->onResume()->Activityis running
5) 切換到别的Activity(目前Activity finish):onPause()->onStop()->onDestroy() 再次啟動時:onCreate()->onStart()->onResume()->Activity isrunning
6)然後按挂機鍵,進入鎖屏界面,然後從鎖屏界面傳回Activity:onPause()->onResume()
7)切換到另一個Activity對話框界面,然後按傳回鍵傳回原來的Activity:onPause()->onResume()
8)啟動本Activity中建立的對話框(彈出Toast和AlertDialog),按傳回鍵從Dialog傳回:Activity的狀态始終未變
9)無論現在是onPause狀态還是onStop狀态,當系統的記憶體不足時,都會将該Activity殺死,當再次進入該Activity重新建立。這意味着,如果發生這種情況,可能我們的onDestroy(如果在停止狀态被殺死),甚至是onStop都沒有得到執行(如果在暫停狀态被殺死),是以,一些重要的資料和狀态,需要在這種情況下也得到儲存,Google為我們專門提供了一個回調函數,就是onSaveInstanceState(Bundle),通過該函數,可以将這些重要的資料在銷毀前進行儲存,然後再onCreate時重新讀
10)橫豎屏切換時候activity的生命周期:
1、不設定Activity的android:configChanges時,切屏會重新調用各個生命周期,切橫屏時會執行一次,切豎屏時會執行兩次
2、設定Activity的android:configChanges="orientation"時,切屏還是會重新調用各個生命周期,切橫、豎屏時隻會執行一次
3、設定Activity的android:configChanges="orientation|keyboardHidden"時,切屏不會重新調用各個生命周期,隻會執行onConfigurationChanged方法
11)當在MainActivity中按back鍵,退出時,或者在代碼中調用finish(),finishActivity()方法,最終就會走到onDestory()。
tips:
在多數情況下,你是不需要顯式地調用finish…()方法去銷毀一個activity。在将要讨論到的activity生命周期裡,你可以知道,Android系統會為你管理activity的生命周期,是以你并不需要顯式銷毀activity(即調用finish類方法)。顯式地調用finish類方法,會對使用者的體驗産生不利的影響,除非你确實是不希望使用者傳回到此activity(界面),才去顯式調用finish類方法。
特殊函數
1. startActivityForResult / onActivityResult / setResult 函數組合
提到這類函數組合,相信隻要有過一段時間Android開發的來說都很熟悉了,此函數組合主要用于如下場景:使用者在A Activity上點選某個按鈕,跳轉到B Activity,然後使用者在B Activity上進行一些具體的操作,待操作完成後傳回到A Activity,同時常常将B Activity中操作的一些資料傳回到A Activity中。
再如上場景中,A -> B 需要通過startActivityForResult()方式打開。具體方式如下:
1 button.setOnClickListener(new View.OnClickListener() {
2 @Override
3 public void onClick(View v) {
4 Intent intent = new Intent(AActivity.this, BActivity.class);
5 startActivityForResult(intent, 1);
6 }
7 });
其中,startActivityForResult第一個參數為Intent,是以,對于需要傳遞額外參數時,可以通過Intent直接傳遞。其中Bundle為可選參數。第二個參數為requestCode,即業務請求碼。
B Activity中,在處理完或相應完使用者操作後,自身結束前,需要通過setResult将資料回傳給A。
1 btnClose.setOnClickListener(new View.OnClickListener() {
2 public void onClick(View v) {
3
4 // 需要傳回的資料存入到intent中
5 Intent intent = new Intent();
6 intent.putExtra("name", "corn");
7
8 //設定傳回資料
9 setResult(RESULT_OK, intent);
10
11 //關閉Activity
12 finish();
13 }
14 });
接下來A接手B回傳的資料。
1 @Override
2 protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
3 String name;
4 // 取得B回傳的資料
5 if(resultCode == RESULT_OK ){
6 name = intent.getStringExtra("name");
7 } else if(resultCode == RESULT_CANCELED){
8 // ...
9 }
10 }
此函數組合中,需要注意如下問題:
1.根據項目的實際需要進行定義,特别需要注意的是,requestCode必須 >= 0,否則此類效果失效,其效果将變成startActivity()效果;
2.resultCode表示B中處理後的結果狀态,系統内部定義了RESULT_OK、RESULT_CANCELED和RESULT_FIRST_USER三種狀态。當然,自己可以定義成任何int型辨別狀态。
3.有時在複雜的業務邏輯中,可能存在A startActivityForResult 到B,同時C也startActivityForResult 到B,且requestCode可能相同(以表示同意業務請求),這時可能需要在B中針對性的判斷此請求來源(來自于A還是C)。此時,可以通過intent傳參形式。相信大家都比較熟悉,其實Activity類中也提供了相應的函數可以擷取到來源Activity的類型函數:getCallingActivity()。但需要注意此函數僅針對startActivityForResult有效,傳回的結果中包含完成包名。
4.A中回調函數調用時機需要注意,其調用發生在B的onPause之後,A的onRestart之前(如果B完成遮住了A),且必然在onResume之前。
5.此函數組合針對B的啟動模式為singleTask或singInstance将會失效。此時,onActivityResult将在A的onpause之後直接回調,且resultCode為RESULT_CANCELED。
2.moveTaskToBack
如《Android總結篇系列:Activity生命周期》一文中有提到的,模拟現在的主流應用最後按Back鍵時不是強制退出應用或直接結束根Activity,而是采取類Home鍵效果,此時可以直接通過此函數實作,非常實用。
1 @Override
2 public void onBackPressed() {
3 moveTaskToBack(true);
4 }
此方法直接将目前Activity所在的Task移到背景,同時保留activity順序和狀态。
3.onNewIntent調用時機
onNewIntent隻有在以下場景才會回調:目前通過Intent方式啟動的Activity不是重新完整建立執行個體,而是複用之前已經存在的執行個體(如被設定了singleTop啟動模式,或FLAG_ACTIVITY_SINGLE_TOP intent flags或設定了Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP等,以此類推,被設定了singleTask或single。此時都會執行到onNewIntent)。onNewIntent調用後,将繼續回調onRestart,onResume...
4.onSaveInstanceState / onRestoreInstanceState調用時機
onSaveInstanceState調用時機:當Activity變得“容易”被系統銷毀時,onSaveInstanceState即被回調,除非該activity是被使用者主動銷毀的,例如當使用者按BACK鍵的時候。
注意上面的雙引号,何為“容易”?言下之意就是該activity還沒有被銷毀,而僅僅是一種可能性。這種可能性有哪些?
1.當使用者按下HOME鍵時;
2.長按HOME鍵,選擇運作其他的程式時;
3.按下電源按鍵(關閉螢幕顯示)時;
4.從activity A中啟動一個新的activity時;
5.螢幕方向切換時,例如從豎屏切換到橫屏時。
onRestoreInstanceState調用時機,activity A“确實”被系統銷毀了,而如果僅僅是停留在有這種可能性的情況下,則該方法不會被調用。另外,onRestoreInstanceState的bundle參數也會傳遞到onCreate方法中,也可以選擇在onCreate方法中做資料還原。
1 @Override
2 protected void onRestoreInstanceState(Bundle savedInstanceState) {
4 super.onRestoreInstanceState(savedInstanceState);
5 savedInstanceState.getString("name", "");
7 }
9 @Override
10 public void onSaveInstanceState(Bundle savedInstanceState) {
11 super.onSaveInstanceState(savedInstanceState);
12 savedInstanceState.putString("name", "corn");
13 }
或在onCreate中:
1 public class AActivity extends ActionBarActivity {
2
3 private String name;
4
5 @Override
6 protected void onCreate(Bundle savedInstanceState) {
7 super.onCreate(savedInstanceState);
8 setContentView(R.layout.a);
9
10 if (savedInstanceState != null) {
11 name = savedInstanceState.getString("name");
12 }
13
14 }
15
16 }
需要注意的是,onSaveInstanceState被調用時,其調用發生在Activity生命周期中具體的位置。以A->B為例,A中onSaveInstanceState調用發生在A:onPause -> B:onCreate -> B:onResume -> A:onSaveInstanceState -> A:onStop。
onSaveInstanceState常常用于存儲應用程式中目前Activity中重要的狀态資料,以免Activity被系統意外殺掉的情況下當使用者再次回來時不能找到之前的狀态。如同一個Activity中使用多個fragment實作菜單功能時,最好需要在此函數中記錄下目前菜單對應的fragment id等。