Android -- Activity官方文檔簡譯

Android -- Activity官方文檔簡譯


主要內容來自官方文檔:Activity


Activity


public class Activity
extendsContextThemeWrapperimplementsLayoutInflater.Factory2,Window.Callback,KeyEvent.Callback, View.OnCreateContextMenuListener, ComponentCallbacks2




Activity是一個用戶能獨立、專心處理的事物。幾乎所有Activity都與用戶交互,所以Activity類會通過調用setContentView(View)來創建一個可以用來放置你的UI的窗口。儘管Activity經常以全屏窗口的形式呈現給用戶,但它們也有其他的使用方法:作爲浮動窗口(通過一個設置了WindowIsFloating的主題)或者嵌入其他Activity中(使用ActivityGroup)。

這裏有兩個幾乎所有Activity子類都會實現的方法:

  • onCreate(Bundle)是你初始化Activity的地方。最重要的,這裏你經常會調用setContentView(int)並傳入一個佈局資源來定義你的UI,並且通過調用findViewById(int)得到UI中在編程時需要交互的組件。
  • onPause()是處理用戶離開你Activity的地方。最重要的,所有用戶行爲導致產生的變化都應該在此節點提交(例如ContentProvider持有數據)。

爲了使用Context.startActivity(),所有Activity類型都必須在包的AndroidManifest.xml中存在對應的<activity>聲明。


Activity生命週期


系統中的Activity以Activity棧的形式管理。當一個新Activity被啓動後,它會被放置在棧的頂部併成爲正在運行的Activity -- 它之前的Activity在棧中總是處於它的下面,並且直到新Activity退出時,它纔會重新返回到前臺。


一個Activity實質上有四中狀態:

  • 如果一個Activity位於屏幕的最前面,它是active的或是running的
  • 如果一個Activity已經失去焦點,但是依然可見,那它是paused的。一個暫停的Activity還是完全存活的(它保留着所有狀態和成員信息,並且仍然和window manager關聯),但是在內存極端底的情況下,它可以被系統殺死。
  • 如果一個Activity完全被其他Activity隱藏,那它是stopped的。它仍然保留着所有狀態和成員信息。由於它對用戶不再可見,所以它的窗口是隱藏的,並且它可以在系統需要內存的任何時間點被殺死。
  • 如果一個Activity是stopped或是paused的,那麼系統可以通過使它finish或者直接殺掉它的進程來丟棄它以獲得內存。當再次被呈現給用戶時,它必須被完全重啓並恢復到之前的狀態。

接下來的圖展示了一個Activity的重要的狀態路徑圖:




其中有三個關鍵的迴路,我們在監測自己的Activity也許會感興趣:

  • 一個Activity的完整生命週期發生在第一次調用onCreate(Bundle)和最終唯一一次調用onDestroy()之間。Activity應該在onCreate()中處理所有的全局初始化,並在onDestroy()中釋放所有持有的資源。例如,假設有一個線程在後臺通過網絡下載數據,那麼應在onCreate()中創建該線程,並在onDestroy()中停止它。
  • 一個Activity的可見生命週期發生在onStart()和onStop()調用之間。在這期間,用戶可以在屏幕上看到該Activity,但它不一定在前臺並和用戶交互。在onStart()和onStop(0之間,我們可以繼續持有那些要在Activity展現給用戶時需要的資源。例如,你可以在onStart()中註冊一個BroadcastReceiver來監聽那些影響你UI的外界變化,並當用戶無法再看到你展現的內容時在onStop()中註銷它。onStart()和onStop()方法可以被多次調用,正如Activity對用戶變換爲可見和隱藏一樣。
  • 一個Activity的前臺(foreground )生命週期發送在onResume()和onPause()調用之間。這期間,Activity處在所有所有其他Activity之前,並和用戶交互。一個Activity可以頻繁地在resumed和paused狀態之間轉換;例如,當設備進入休眠,或者某個Activity result被拋出,或者一個新Intent被拋出時 -- 所以這些方法中應儘量只包含輕量級的代碼。

接下來的Activity接口定義了一個Activity的完整生命週期。它們是一組“鉤子”接口,你可以覆寫它們,以便在Activity改變狀態時做一些相應的工作。所有的Activity都會實現onCreate(Bundle)來完成它們的初始化步驟。許多Activity也會實現onPause()方法來提交變化的數據或者做一些工作以準備停止和用戶交互。在實現這些方法時,你總是需要先調用父類中的該同名方法。

 public class Activity extends ApplicationContext {
     protected void onCreate(Bundle savedInstanceState);

     protected void onStart();

     protected void onRestart();

     protected void onResume();

     protected void onPause();

     protected void onStop();

     protected void onDestroy();
 }

通常情況下,貫穿Activity生命週期的一個回調轉移過程如下所示:


Method Description Killable? Next
onCreate() Activity第一創建時調用。我們應該在該函數中做一般的初始化工作,如創建各個View對象、爲列表綁定數據等。如果有的話,這個方法總是會提供你一個包含之前Activity凍結狀態的Bundle對象。onStart()方法總是在該方法之後。 No onStart()
  onRestart() 在Activity停止之後,重新啓動之前被調用。它之後總是調用onStart()方法。 No onStart()
onStart() 在Activity即將對用戶可見時調用。如果Activity即將前臺顯著位置,那它之後是onResume()方法;如果Activity被隱藏,那它之後是onStop()方法。 No onResume() or onStop()
  onResume() 當Activity即將開始和用戶交互時,它會被調用。此時,你的Activity會在棧的最頂端,用戶可以對它進行輸入操作。它之後總是onPause()調用。 No onPause()
onPause() 當系統開始(esume一個之前的Activity時,它會被調用。典型的,我們一般在此執行保存數據、關閉動畫或其他某些消耗CPU資源的動作。該方法的執行必須非常快速,因爲下一個Activity只會在該方法完成並返回後,纔會被resume。如果Activity接下來返回到屏幕前臺,那麼它接下來是onResume()方法;如果Activity變成對用戶不可見,那它之後是onStop()方法。 Pre-HONEYCOMB onResume() or
onStop()
onStop() 當一個Activity不再對用戶可見時,該方法會被調用;因爲另一個Activity會被resume並覆蓋到它之上。這個方法也會在當一個Activity正在被啓動,但此時另一個存在的Activity被直接處理到它之前,或者這個Activity即將被銷燬時調用。如果一個Activity即將重新回到前臺與用戶交互,那它之後是onRestart()調用;如果這個Activity即將被銷燬,那它之後是onDestroy()調用。 Yes onRestart() or
onDestroy()
onDestroy() 這是你的Activity在銷燬之前,你能接收到的最後一個函數調用。當用戶調用finish(),或者系統爲了節省空間,需要暫時銷燬該Activity實例時,你的Activity纔會被銷燬。你可以通過isFinishing()方法來區分這兩種場景。 Yes nothing


注意表中的“Killable”一欄 -- 對於那些被標記爲“killable”的方法,在這些方法返回之後,持有該Activity的進程可能會在不執行任何其他一行該Activity的代碼的情況下被系統殺死。因此,你需要在onPause()中保存任何修改過的並需要保存的數據。除此之外,onSaveInstanceState(Bundle)會在該Activity轉變成後臺狀態之前被調用,這允許你在給定的Bundle中,保存任何你Activity中的動態實例狀態信息;之後當該Activity需要再次被創建時,你可以在onCreate(Bundle)中重新接收它們。我們需要注意的一點是,我們應該在onPause(),而不是onSaveInstanceState(Bundle)中,保存那些持久性數據;因爲後者並不是生命週期回調的一部分,所以它並不會在文檔中描述的每一個場景中都被調用。


對於那些沒有被標記爲“killable”的方法,Activity所在的進程在該方法調用開始並在它返回之後,都不會被系統殺死。因此,舉個例子:一個Activity在onPause()之後,onResume()調用之前,它都處於進程可被殺死的狀態。


啓動Activity並獲取結果


startActivity(Intent)方法可以用來啓動Activity,它將會被放置在Activity棧的頂端。方法只需要一個Intent參數,它描述了需要被執行的Activity。


有時候你會想要從一個結束的Activity中得到一個返回結果。例如,你會開啓一個Activity讓用戶從聯繫人列表中選擇一個人;當該Activity結束時,讓它返回被選中的結果。爲了實現這種情況,你需要調用startActivityForResult(Intent, int)版本,它附帶了一個定義此次調用請求的int型參數。該調用結果會通過onActivityResult(int, int, Intent)方法返回。


當一個Activity退出時,它可以調用setResult(int)向它的父Activity返回數據。它必須總是提供一個結果碼,這可以是標準定義結果碼 RESULT_CANCEELD/RESULT_OK,或者任何從RESULT_FIRST_USER開始的客戶值。除此之外,這個Activity可以隨意返回一個包含任何它期望的數據的Intent給父Activity。所有的這些信息都會在父Activity的onActivityResult()函數中出現,同時它也會附帶之前提供的對此次調用的請求碼。


如果子Activity由於諸如崩潰的原因運行失敗了,它的父Activity將會收到一個帶有RESULT_CANCELED碼值的結果。

public class MyActivity extends Activity {
     ...

     static final int PICK_CONTACT_REQUEST = 0;

     public boolean onKeyDown(int keyCode, KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
             // When the user center presses, let them pick a contact.
             startActivityForResult(
                 new Intent(Intent.ACTION_PICK,
                 new Uri("content://contacts")),
                 PICK_CONTACT_REQUEST);
            return true;
         }
         return false;
     }

     protected void onActivityResult(int requestCode, int resultCode,
             Intent data) {
         if (requestCode == PICK_CONTACT_REQUEST) {
             if (resultCode == RESULT_OK) {
                 // A contact was picked.  Here we will just display it
                 // to the user.
                 startActivity(new Intent(Intent.ACTION_VIEW, data));
             }
         }
     }
 }


進程生命週期


Android系統會嘗試儘可能地保存應用程序進程,但是當系統內存很低時,它最終也會去移除一些老的進程。正如Activity生命週期部分所描述的,決定移除哪一個進程跟用戶與進程的交互狀態密切相關。一般情況下,基於運行其中的Activity,一個進程可以有4種狀態,下面以重要性爲序列出。系統會按重要性從低(最後一個)到高(第一個)的順序殺死應用進程。

  1. 前臺Activity(處在屏幕頂端並與用戶交互的Activity)被認爲是最重要的。如果它使用的內存超過了設備上可獲取的最大值,那麼它的進程會在萬不得已的情況下被殺死。通常情況下,此時設備已經達到了內存分頁狀態,所以它需要按序保持用戶接口可響應。
  2. 一個可見的Activity(對用戶可見但不處於前臺狀態)也是非常重要的,除非到了需要殺死它來維持前臺Activity運行的地步,一般情況下,系統都不會去制裁它。
  3. 一個後臺Activity(不在對用戶可見並處於paused狀態)的狀態不再是危險的了,所以爲了給其他前臺或可見的進程回收內存,系統可以安全地殺死它所屬的進程。如果它的進程將要被殺死,當用戶操作並返回到它這個Activity時,它的onCreate(Bundle)函數將被調用,並且之前在它的onSaveInstanceState(Bundle)中提供的savedInstanceState信息也會被接收到;所以它可以將自己重啓到之前的狀態,就如用戶離開它時的那樣。
  4. 沒有運行任何Activity或其他應用組件(如Service或BroadcastReceiver)的進程是一個空進程。當系統內存變低的時候,它們很快會被系統殺死。基於這點,你的任何在Activity之外運行的後臺操作都需要在一個BroadcastReceiver或Service中執行,以確保系統知道它需要保持你的這個進程。


1、startActivityForResult(Intent intent, int resquestCode, Bundle options)


啓動一個當它結束時你期望從它得到一個返回結果的Activity。當啓動的Activity退出時,你的onActivityResult()方法會附requestCode參數被調用。如果你調用時使用的requestCode是負值,那它效果等同於startActivity(Intent)。


需要注意的是,該方法只有當你使用被定義成會返回結果的Intent協議時才應當被使用。在其他協議中(如ACTION_MAIN或者ACTION_VIEW),你也許並不會如期望地那樣得到一個結果。如果你啓動Activity時使用了FLAG_ACTIVITY_NEW_TASK標誌,那麼它將不會運行在你當前的Activity棧中,你會立即收到一個CANCELED結果。


作爲一個特殊的例子,如果你在Activity的onCreate()/onResume()方法中,使用了一個大於等於0的requestCode參數去調用startActivityForResult();此時你的窗口只會在從啓動的Activity中得到一個結果之後,它纔會顯示出來。這樣可以避免當重定向到其他Activity時,屏幕會產生可見的閃爍。


Parameters
intent Intent: The intent to start.
requestCode int: If >= 0, this code will be returned in onActivityResult() when the activity exits.
options Bundle: Additional options for how the Activity should be started. See startActivity(Intent, Bundle) Context.startActivity(Intent, Bundle)} for more details.

This value may be null.


該函數一般與setResult(int requestCode, Intent data)結合使用。


2、onSaveInstanceState(Bundle outState)


用來得到一個Activity被殺死之前的某些狀態,確保在該Activity被重新啓動時,在onCreate(Bundle)/onRestoreInstanceState(Bundle)中,它可以根據Bundle中的信息重新恢復到被殺死之前的狀態(Bundle對象通常會被同時傳遞給這兩個方法)。


這個方法一般在某個Activity即將被殺死之前調用,所以將來當它重新迴歸時,它可以恢復它之前的狀態。例如,Activity B被啓動,並處在Activity A的前面,某個時間點爲了回收資源,Activity A被殺死了;Activity會有一個通過該方法保存當前它的用戶接口當前狀態的機會,所以當用戶重新返回到Activity A時,它的用戶接口狀態可以通過onCreate(Bundle)/onRestoreInstanceState(Bundle)接口重新得到恢復。


不要對該方法和Activity生命週期回調函數產生困惑(如onPause(),它總是在Activity被轉入後臺或即將被銷燬時調用;如onStop(),總是在Activity銷燬之前調用)。一個onPause()、onStop()方法會被調用,而onSaveInstanceState(Bundle)不會被調用的例子就是:用戶手動將Activity A操作到Activity B之前;此時沒有必要在Activity B上調用onSaveInstanceState()函數,因爲此時沒有需要保存的特定信息,所以系統就會避免去調用它。一個onPause()被調用,而onSaveInstanceState()不會的場景就是Activity B被啓動,並且運行在Activity A之前;如果Activity A在Activity B的生命週期內沒有被系統殺死,那麼它的onSaveInstanceState()不會被調用,因爲Activity A此時的用戶接口狀態並不會改變。


如果onSaveInstanceState()被調用,那麼它會發生在onStop()之前。我們無法保證它的調用是否會發生在onPause()之前或之後。


3、onRestoreInstanceState(Bundle saveInstanceState)


當一個Activity被重新初始化爲之前的狀態時(saveInstanceState提供),它會在onStart()之後被調用。大多數時候,我們會簡單實現onCreate(Bundel)來恢復Activity的狀態;但有些時候在所有初始化工作都完成後,再在該函數中進行狀態恢復,或者允許子類自己決定如何使用函數的默認實現,都是很方便的。該函數的默認實現就是將Activity的任何View狀態恢復到之前onSaveInstanceState(Bundle)被調用時這些View最後凍結的狀態那樣。


該函數在onStart()和onPostCreate(Bundle)之間被調用。


發佈了72 篇原創文章 · 獲贊 68 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章