Activity作為Android系統中四大基本組件之一,包含大量的與其他的各大組件、intent、widget以及系統各項服務等之間的交互的函數。在此,本文主要選取實際項目開發中常用的,但完全理解又需要有一定深入了解的幾個函數進行講解,后續本文會根據需要不斷更新。
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) { 3 // TODO Auto-generated method stub
4 super.onRestoreInstanceState(savedInstanceState); 5 savedInstanceState.getString("name", ""); 6
7 } 8
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等。