【Android必備】Activity的生命週期(2)

瞭解Activity生命週期


當用戶瀏覽,瀏覽並返回到您的應用程序時,應用程序中的 Activity實例將在其生命週期中的不同狀態中轉換。的Activity類提供了一些回調允許Activity知道一個狀態已經改變的:該系統被創建,停止或恢復活性,或破壞該Activity所在的過程。

在生命週期回調方法中,您可以聲明用戶離開並重新進入Activity時Activity的行爲。例如,如果您正在構建流媒體視頻播放器,則可能會暫停視頻並在用戶切換到其他應用時終止網絡連接。當用戶返回時,您可以重新連接到網絡並允許用戶從同一地點恢復視頻。換句話說,每個回調允許您執行適合於給定狀態更改的特定工作。在正確的時間做適當的工作並正確地處理轉換,可以使您的應用更加健壯和高效。例如,生命週期回調的良好實現可以幫助確保您的應用程序避免:

  • 如果用戶在使用應用程序時收到電話或切換到其他應用程序,則會崩潰。
  • 當用戶沒有使用它時消耗寶貴的系統資源。
  • 如果用戶離開您的應用程序並在稍後返回,則會丟失用戶的進度。
  • 當屏幕在橫向和縱向之間旋轉時,會損壞或丟失用戶的進度。

本文檔詳細解釋了Activity生命週期。該文件從描述生命週期範式開始。接下來,它解釋了每個回調:它們執行時在內部發生了什麼,以及它們應該執行什麼。然後簡要介紹Activity狀態與進程被系統殺死的脆弱性之間的關係。最後,它討論了與Activity狀態之間的轉換有關的幾個主題。

有關處理生命週期的信息(包括最佳實踐指南),請參閱 使用生命週期感知組件處理生命週期以及保存UI狀態。要了解如何使用與架構組件結合的Activity來構建強大的生產質量的應用程序,請參閱 應用程序架構指南

Activity生命週期概念


到的活性生命週期的階段之間導航的過渡,Activity類別提供一組核心六個回調: onCreate(), onStart(), onResume(), onPause(), onStop(),和 onDestroy()。當Activity進入新狀態時,系統調用每個回調。
【Android必備】Activity的生命週期(2)
圖1展示了這種範例的視覺表現。
當用戶開始離開Activity時,系統會調用方法來解除Activity。在某些情況下,這種拆除只是部分; 該Activity仍駐留在內存中(例如,當用戶切換到另一個應用程序時),並且仍然可以回到前臺。如果用戶返回到該Activity,則該Activity從用戶離開的地方恢復。系統殺死一個給定過程的可能性 - 以及其中的Activity - 取決於當時Activity的狀態。Activity狀態和記憶彈射提供了關於狀態與彈射脆弱性之間關係的更多信息。

根據您的Activity的複雜程度,您可能不需要實施所有生命週期方法。但是,重要的是要了解每個人並實施那些可確保您的應用按用戶期望的方式行事的人。

本文檔的下一部分詳細介紹了用於處理狀態之間轉換的回調。

生命週期回調


本節提供有關在Activity生命週期中使用的回調方法的概念和實現信息。

某些操作(如調用)屬於Activity生命週期方法本身。但是,實現相關組件操作的代碼應該放置在組件本身中。爲了實現這一點,您必須使依賴組件的生命週期感知。請參閱 使用生命週期感知組件處理生命週期以瞭解如何使您的從屬組件生命週期感知。 setContentView()

onCreate()

您必須實現此回調,當系統首次創建Activity時觸發回調。在Activity創建時,Activity進入創建狀態。在該onCreate() 方法中,您可以執行基本的應用程序啓動邏輯,這些邏輯應該在Activity的整個生命週期中只發生一次。例如,您的實現可能會將數據綁定到列表,將該Activity與a關聯 ,並實例化一些類作用域變量。此方法接收參數,該參數是 包含Activity先前保存狀態的對象。如果Activity從未存在過,則該對象的值爲空。 onCreate()ViewModelsavedInstanceStateBundleBundle

如果您有一個與生命週期相關的生命週期感知組件,它將收到該 ON_CREATE 事件。用@OnLifecycleEvent註解的方法將被調用,以便您的生命週期感知組件可以執行創建狀態所需的任何設置代碼。

下面的onCreate()方法示例 顯示了該Activity的基本設置,例如聲明用戶界面(在XML佈局文件中定義),定義成員變量以及配置一些UI。在這個例子中,XML佈局文件是通過傳遞文件的資源ID R.layout.main_activity來 指定的setContentView()。

TextView mTextView;

// some transient state for the activity instance 
String mGameState;

@Override 
public void onCreate(Bundle savedInstanceState) {
    // call the super class onCreate to complete the creation of activity like 
    // the view hierarchy 
    super.onCreate(savedInstanceState);

    // recovering the instance state 
    if (savedInstanceState != null) {
        mGameState = savedInstanceState.getString(GAME_STATE_KEY);
    } 

    // set the user interface layout for this activity 
    // the layout file is defined in the project res/layout/main_activity.xml file 
    setContentView(R.layout.main_activity);

    // initialize member TextView so we can manipulate it later 
    mTextView = (TextView) findViewById(R.id.text_view);
} 

// This callback is called only when there is a saved instance that is previously saved by using 
// onSaveInstanceState(). We restore some state in onCreate(), while we can optionally restore 
// other state here, possibly usable after onStart() has completed. 
// The savedInstanceState Bundle is same as the one used in onCreate(). 
@Override 
public void onRestoreInstanceState(Bundle savedInstanceState) {
    mTextView.setText(savedInstanceState.getString(TEXT_VIEW_KEY));
} 

// invoked when the activity may be temporarily destroyed, save the instance state here 
@Override 
public void onSaveInstanceState(Bundle outState) {
    outState.putString(GAME_STATE_KEY, mGameState);
    outState.putString(TEXT_VIEW_KEY, mTextView.getText());

    // call superclass to save any view hierarchy 
    super.onSaveInstanceState(outState);
} 

作爲定義XML文件並傳遞給它的替代方法setContentView(),您可以View在您的Activity代碼中創建新對象,並通過將新的Views 插入到a中來 構建視圖層次結構ViewGroup。然後通過傳遞根ViewGroup來 使用該佈局setContentView()。有關創建用戶界面的更多信息,請參閱 用戶界面【原】文檔。

您的Activity不處於創建狀態。該onCreate()方法完成執行後,Activity進入啓動 狀態,系統將快速連續調用onStart() 和onResume()方法。下一節解釋 onStart()回調。

onStart()

當Activity進入開始狀態時,系統調用此回調。該onStart()調用使用戶可以看到該Activity,因爲該應用程序準備進入前臺併成爲交互式Activity。例如,此方法是應用程序初始化維護UI的代碼的位置。

當Activity移動到開始狀態時,與Activity生命週期關聯的任何生命週期感知組件都將收到該 ON_START事件。

該onStart()方法非常快速地完成,並且與創建狀態一樣,該Activity不會保持駐留在已啓動狀態。一旦這個回調完成,Activity進入 恢復狀態,系統調用該 onResume()方法。

onResume()

當Activity進入恢復狀態時,它進入前臺,然後系統調用onResume() 回調。這是應用程序與用戶交互的狀態。該應用停留在這種狀態,直到發生某些事情將焦點從應用中移開。例如,這種事件可能是接到電話,用戶導航到其他Activity或設備屏幕關閉。

當Activity轉移到恢復狀態時,與Activity生命週期關聯的任何生命週期感知組件都將收到該 ON_RESUME 事件。這是生命週期組件可以在組件可見並且處於前臺時啓用需要運行的任何功能的位置,例如啓動相機預覽。
Activity
當發生中斷事件時,ActivityActivity進入暫停 狀態,系統調用 onPause()回調。

如果ActivityActivity從暫停狀態返回到恢復狀態,則系統再次調用 onResume()方法。因此,您應該實現onResume() 初始化您在釋放期間發佈的組件 onPause(),並執行每次Activity進入恢復狀態時必須發生的任何其他初始化。

以下是組件接收ON_RESUME事件時訪問攝像頭的生命週期感知組件的示例 :

public class CameraComponent implements LifecycleObserver {

    ...

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void initializeCamera() {
        if (camera == null) {
            getCamera();
        }
    }

    ...
}

上面的代碼初始化相機一次 LifecycleObserver 接收ON_RESUME事件。但是,在多窗口模式下,即使處於暫停狀態,您的Activity也可以完全可見。例如,當用戶處於多窗口模式並點擊另一個不包含您的Activity的窗口時,您的Activity將移至暫停狀態。如果您希望相機僅在應用程序恢復時處於Activity狀態(在Activity前景中可見並處於Activity狀態),請在上面顯示的ON_RESUME事件之後初始化相機。如果您希望在Activity暫停但可見的情況下保持攝像機處於Activity狀態(例如,在多窗口模式下),則應該在ON_START事件之後初始化攝像機。但請注意,如果在您的Activity暫停時讓相機處於Activity狀態,則可能會拒絕在多窗口模式下將相機訪問到另一個恢復的應用程序。有時可能需要在您的ActivityActivity暫停時保持相機處於Activity狀態,但如果您這樣做,則實際上可能會降低整體用戶體驗。仔細考慮在生命週期的哪個地方更適合在多窗口環境中控制共享系統資源。要了解更多關於支持多窗口模式的信息,請參閱多窗口支持。

無論您選擇在哪個構建事件中執行初始化操作,請確保使用相應的生命週期事件釋放資源。如果您在ON_START事件之後初始化某些內容,請在ON_STOP事件之後釋放或終止它。如果您在ON_RESUME事件之後進行初始化,請在ON_PAUSE事件之後釋放。

請注意,上面的代碼片段將攝像機初始化代碼放置在生命週期感知組件中。您可以直接將此代碼放入Activity生命週期回調中,例如 onStart(), onStop()但不建議這樣做。將此邏輯添加到獨立的支持生命週期的組件中,可讓您跨多個Activity重用組件,而無需複製代碼。請參閱 使用生命週期感知組件處理生命週期Activity 以瞭解如何創建生命週期感知組件。

onPause()

系統調用此方法作爲用戶離開Activity的第一個指示(儘管它並不總意味着Activity正在被銷燬); 它表明該Activity不再處於前臺(儘管如果用戶處於多窗口模式,它仍然可見)。onPause()當Activity處於暫停狀態時,使用該方法暫停或調整不應該繼續(或者應該繼續適度)的操作,並且您希望很快恢復。Activity可能會進入此狀態有幾個原因。例如:

  • 正如onResume()部分所述,某些事件會中斷應用程序的執行。這是最常見的情況。
  • 在Android 7.0(API等級24)或更高版本中,多個應用程序以多窗口模式運行。因爲任何時候只有其中一個應用程序(窗口)有焦點,系統會暫停所有其他應用程序。
  • 一個新的,半透明的Activity(如對話框)打開。只要該Activity仍然部分可見但不重點,它仍然處於暫停狀態。

當Activity轉到暫停狀態時,與Activity生命週期關聯的任何生命週期感知組件都將收到該 ON_PAUSE事件。這是生命週期組件可以停止在組件不在前臺運行時不需要運行的任何功能的地方,例如停止相機預覽。
Activity
您也可以使用此 onPause()方法釋放系統資源,傳感器的手柄(如GPS),或在Activity暫停並且用戶不需要它們時可能影響電池壽命的任何資源。但是,如上面在onResume()部分中所述,如果在多窗口模式下,暫停的Activity仍可以完全可見。因此,您應該考慮使用onStop()而不是onPause()來完全釋放或調整與UI相關的資源和操作,以更好地支持多窗口模式。

以下LifecycleObserver 響應ON_PAUSE事件的示例是上述ON_RESUME事件示例的對應部分,釋放在收到ON_RESUME事件後初始化的攝像頭:

public class JavaCameraComponent implements LifecycleObserver {

    ...

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void releaseCamera() {
        if (camera != null) {
            camera.release();
            camera = null;
        }
    }

    ...
}

請注意,在LifecycleObserver接收到ON_PAUSE事件後,上面的代碼片段會放置相機發布代碼。如前所述,請參閱 使用生命週期感知組件處理生命週期 以瞭解如何創建生命週期感知組件。

onPause()執行非常簡短,並且不一定有足夠的時間執行保存操作。出於這個原因,你應該不使用 onPause()保存應用程序或用戶數據,進行網絡通話,或執行數據庫事務; 在方法完成之前,這樣的工作可能無法完成。相反,您應該在執行重負載關閉操作期間 onStop()。有關在執行期間執行的合適操作的更多信息 onStop(),請參閱 onStop()。有關保存數據的更多信息,請參閱 保存和恢復Activity狀態。

Activity該onPause()方法的完成並不意味着Activity離開暫停狀態。而是,Activity保持這種狀態,直到Activity恢復或對用戶完全不可見爲止。如果Activity恢復,系統再次調用onResume()回調。如果Activity從暫停狀態返回到恢復狀態,則系統將Activity實例駐留在內存中,並在系統調用時調用該實例 onResume()。在這種情況下,您不需要重新初始化任何導致恢復狀態的回調方法中創建的組件。如果Activity完全不可見,則系統調用 onStop()。下一節討論onStop()回調。

onStop()

當您的Activity對用戶不再可見時,它已進入 停止狀態,並且系統調用 onStop()回調。例如,當新推出的Activity覆蓋整個屏幕時,可能會發生這種情況。系統也可能onStop() 在Activity完成並即將終止時調用。

當Activity進入停止狀態時,與Activity生命週期關聯的任何生命週期感知組件都將收到該 ON_STOP事件。這是生命週期組件可以停止在組件在屏幕上不可見時不需要運行的任何功能的地方。

在該onStop()方法中,應用程序應釋放或調整應用程序對用戶不可見時不需要的資源。例如,您的應用可能會暫停動畫或從細粒度切換到粗粒度位置更新。 即使用戶在多窗口模式下查看您的Activity,使用 onStop()而不是onPause()確保與用戶界面相關的工作仍在繼續。

您還應該使用onStop() 執行相對CPU密集型關機操作。例如,如果您找不到更合適的時間將信息保存到數據庫,那麼您可能會在此期間這樣做onStop()。以下示例顯示了其中的一個實現 onStop()將草稿備註的內容保存到持久性存儲:

@Override 
protected void onStop() { 
    // call the superclass method first 
    super.onStop(); 

    // save the note's current draft, because the activity is stopping 
    // and we want to be sure the current note progress isn't lost. 
    ContentValues values = new ContentValues();
    values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText());
    values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle());

    // do this update in background on an AsyncQueryHandler or equivalent 
    mAsyncQueryHandler.startUpdate ( 
            mToken,  // int token to correlate calls 
            null,    // cookie, not used here 
            mUri,    // The URI for the note to update. 
            values,  // The map of column names and new values to apply to them.
            null,    // No SELECT criteria are used. 
            null     // No WHERE columns are used. 
    ); 
} 

請注意,上面的代碼示例直接使用SQLite。你應該使用Room,一個持久性庫,它提供了一個SQLite抽象層。要詳細瞭解使用Room的好處以及如何在應用中實現Room,請參閱 Room Persistence Library 指南。

當您的Activity進入停止狀態時,該Activity 對象將保持駐留在內存中:它維護所有狀態和成員信息,但未附加到窗口管理器。當Activity恢復時,Activity將回收此信息。您不需要重新初始化任何導致恢復狀態的回調方法期間創建的組件。系統還會跟蹤View佈局中每個對象的當前狀態,因此如果用戶將文本輸入到EditText小部件中,則會保留該內容,因此您無需保存和恢復它。

注意:一旦您的Activity停止,如果系統需要恢復內存,系統可能會銷燬包含該Activity的進程。即使系統在Activity停止時銷燬進程,系統仍然會將View 對象的狀態(如EditText小部件中的文本)保留在 Bundle(一組鍵值對中),並在用戶返回時恢復它們Activity。有關恢復用戶返回的Activity的更多信息,請參閱 保存和恢復Activity狀態。

從停止狀態,Activity要麼回到與用戶交互,要麼Activity完成運行並消失。如果Activity回來,系統會調用onRestart()。如果Activity完成運行,則系統調用 onDestroy()。下一節解釋onDestroy() 回調。

onDestroy()

onDestroy()在Activity被破壞之前調用。系統調用此回調,因爲:

  1. Activity正在完成(由於用戶完全放棄Activity或由於 finish()被稱爲Activity),或者
  2. 系統會暫時破壞由於配置更改(如設備旋轉或多窗口模式)導致的Activity,

當Activity進入停止狀態時,與Activity生命週期關聯的任何生命週期感知組件都將收到該 ON_DESTROY事件。這是生命週期組件在銷燬Activity之前可以清理所需的任何內容的位置。

與其將邏輯放入您的Activity中以確定其銷燬原因,您應該使用ViewModel對象來包含Activity的相關視圖數據。如果Activity將因配置更改而重新創建,則ViewModel無需執行任何操作,因爲它將被保留並提供給下一個Activity實例。如果Activity不會被重新創建,那麼ViewModel將會onCleared()調用這個 方法,它可以在被銷燬之前清理它需要的所有數據。

您可以使用該isFinishing()方法區分這兩種情況 。

如果Activity正在結束,則onDestroy()是Activity接收的最終生命週期回調。如果onDestroy()作爲配置更改的結果被調用,系統會立即創建一個新的Activity實例,然後 在新配置中調用 該新實例。 onCreate()

該onDestroy() 回調應釋放還沒有被釋放由以前的回調,如所有資源onStop()。

Activity狀態和從記憶中彈出


系統在需要釋放RAM時會終止進程; 系統殺死給定進程的可能性取決於當時進程的狀態。進程狀態又取決於進程中運行的Activity的狀態。表1顯示了進程狀態,Activity狀態和系統殺死進程的可能性之間的相關性。
【Android必備】Activity的生命週期(2)
表1.流程生命週期與Activity狀態之間的關係

系統不會直接殺死一個Activity來釋放內存。相反,它會殺死Activity運行的過程,不僅會摧毀Activity,還會摧毀流程中運行的所有其他Activity。要了解在發生系統啓動的進程死亡時如何保留和恢復Activity的UI狀態,請參閱保存和恢復Activity狀態。

用戶也可以通過使用“設置”下的“應用程序管理器”來終止相應應用程序來終止進程。

有關一般進程的更多信息,請參閱 進程和線程。有關流程生命週期如何與其中的Activity狀態關聯的更多信息,請參閱該頁面的 流程生命週期部分。

保存和恢復瞬態UI狀態


用戶期望Activity的UI狀態在整個配置更改期間保持不變,例如旋轉或切換到多窗口模式。但是,當這種配置更改發生時,系統會默認銷燬Activity,並刪除存儲在Activity實例中的任何UI狀態。同樣,如果用戶暫時將應用程序從應用程序切換到其他應用程序,然後再回到應用程序,用戶希望UI狀態保持不變。但是,當用戶離開並且您的Activity停止時,系統可能會破壞您的應用程序的進程。

當Activity被破壞,由於系統的限制,你應該使用的組合保存用戶的瞬時UI狀態 ViewModel, 和/或本地存儲。要了解有關用戶期望與系統行爲的更多信息,以及如何最好地保留跨系統啓動的Activity和進程死亡的複雜UI狀態數據,請參閱 保存UI狀態。 onSaveInstanceState()

本節概述什麼是實例狀態,以及如何實現onSaveInstance()方法,這是對Activity本身的回調。如果您的UI數據是簡單輕量的,比如原始數據類型或簡單對象(如String),那麼您可以單獨使用onSaveInstanceState()來跨越配置更改和系統啓動的進程終止來保持UI狀態。不過,在大多數情況下,您應該使用ViewModel和onSaveInstanceState()(如 保存UI狀態所述),因爲onSaveInstanceState()會導致序列化/反序列化成本。

Activity實例狀態

有幾種情況會導致您的Activity由於正常的應用程序行爲而遭到破壞,例如用戶按下“後退”按鈕或者您的Activity通過調用finish() 方法表示其自身銷燬 。當您的Activity因用戶按下“後退”或Activity自行完成而被銷燬時,系統和用戶對該Activity實例的概念都將永遠消失。在這些情況下,用戶的期望與系統的行爲相匹配,並且您沒有任何額外的工作要做。

但是,如果系統由於系統限制(例如配置更改或內存壓力)而破壞Activity,則儘管實際 Activity 實例不存在,但系統還是會記住它存在。如果用戶嘗試導航回Activity,系統將使用一組保存的數據創建該Activity的新實例,該數據描述Activity在銷燬時的狀態。

系統用於恢復先前狀態的已保存數據稱爲實例狀態,是存儲在Bundle對象中的鍵值對的集合。默認情況下,系統使用Bundle實例狀態來保存有關ViewActivity佈局中每個對象的信息(例如輸入到EditText窗口小部件中的文本值 )。因此,如果您的Activity實例被銷燬並重新創建,那麼佈局的狀態將恢復到之前的狀態,並且不需要您的代碼。但是,您的Activity可能包含更多想要恢復的狀態信息,例如跟蹤用戶Activity進度的成員變量。

注意:爲了使Android系統恢復Activity中視圖的狀態,每個視圖必須具有由android:id屬性提供的唯一ID 。

一個Bundle對象不適合保存多餘數量的數據,因爲它需要在主線程上進行序列化並消耗系統進程內存。要保留超過極少量的數據,您應該採用綜合方法來保存數據,使用持久本地存儲, onSaveInstanceState() 方法和 類,如 保存UI狀態所述。 ViewModel

使用onSaveInstanceState()保存簡單輕量級的UI狀態

當您的Activity開始停止時,系統會調用該 onSaveInstanceState() 方法,以便您的Activity可以將狀態信息保存到實例狀態包中。此方法的默認實現可以保存有關Activity視圖層次結構狀態的瞬態信息,例如EditText小部件中的文本或小部件的滾動位置 ListView。

爲了保存Activity的其他實例狀態信息,必須覆蓋 onSaveInstanceState() 並添加鍵值對,以便Bundle在事件意外銷燬時保存該對象。如果您重寫onSaveInstanceState(),則如果您希望默認實現保存視圖層次結構的狀態,則必須調用超類實現。例如:

static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
// ... 

@Override 
public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save the user's current game state 
    savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
    savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);

    // Always call the superclass so it can save the view hierarchy state 
    super.onSaveInstanceState(savedInstanceState);
} 

Note: 當用戶明確關閉Activity或在其他情況下調用時 不會調用finish(),則不會再調用 onSaveInstanceState()。

要保存持久性數據(例如用戶首選項或數據庫數據),當您的Activity處於前臺時,應該採取適當的機會。如果沒有這樣的機會出現,您應該在該onStop()方法期間保存這些數據 。

使用保存的實例狀態恢復Activity UI狀態

當您的Activity在之前被銷燬之後重新創建時,您可以從Bundle系統傳遞到您的Activity中恢復已保存的實例狀態。無論是 onCreate()和 回調方法收到同樣的 包含實例狀態信息。 onRestoreInstanceState()Bundle

由於 調用方法是否系統正在創建Activity的新實例或重新創建前一個實例,因此必須在嘗試讀取狀態之前檢查狀態Bundle是否爲空。如果它爲空,那麼系統正在創建一個Activity的新實例,而不是恢復之前被銷燬的實例。 onCreate()

例如,下面的代碼片段顯示瞭如何恢復一些狀態數據: onCreate()

@Override 
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); // Always call the superclass first

    // Check whether we're recreating a previously destroyed instance 
    if (savedInstanceState != null) {
        // Restore value of members from saved state 
        mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
        mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
    } else { 
        // Probably initialize members with default values for a new instance 
    } 
    // ... 
} 

您可以選擇執行 ,而不是在系統調用方法之後 恢復狀態 。系統 僅在存在保存狀態才能恢復的情況下調用 ,因此不需要檢查是否爲空: onCreate() onRestoreInstanceState()onStart() onRestoreInstanceState()Bundle

public void onRestoreInstanceState(Bundle savedInstanceState) {
    // Always call the superclass so it can restore the view hierarchy 
    super.onRestoreInstanceState(savedInstanceState);

    // Restore state members from saved instance 
    mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
    mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
} 

警告:始終調用超類實現onRestoreInstanceState(), 以便默認實現可以恢復視圖層次結構的狀態

在Activity之間進行導航


應用程序可能會在應用程序的整個生命週期中進入或退出一個Activity,可能很多次。例如,用戶可以點擊設備的後退按鈕,或者該Activity可能需要啓動不同的Activity。本部分介紹實施成功Activity轉換時需要了解的主題。這些主題包括從其他Activity開始Activity,保存Activity狀態以及恢復Activity狀態。

從另一個開始一個Activity

一個Activity通常需要在某個時候開始另一項Activity。例如,當應用程序需要從當前屏幕移動到新屏幕時,就會出現這種需求。

取決於您的Activity是否想要從新Activity返回的結果即將開始,您可以使用startActivity() 或 startActivityForResult() 方法開始新Activity 。無論哪種情況,您都會傳入一個Intent對象。

該Intent對象指定要開始的確切Activity或描述您要執行的操作的類型(並且系統會爲您選擇適當的Activity,甚至可能來自不同的應用程序)。一個Intent對象還可以攜帶少量的數據供啓動的Activity使用。有關Intent該類的更多信息,請參閱 Intents和Intent Filters

startActivity()

如果新開始的Activity不需要返回結果,則當前Activity可以通過調用該startActivity() 方法來啓動它 。

在您的應用程序中工作時,您經常需要簡單地啓動已知的Activity。例如,以下代碼片段顯示瞭如何啓動一個名爲的Activity SignInActivity。

Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);

您的應用程序可能還希望使用您的Activity中的數據執行某些操作,例如發送電子郵件,短信或狀態更新。在這種情況下,您的應用程序可能沒有自己的Activity來執行此類操作,因此您可以利用設備上的其他應用程序提供的Activity,它們可以爲您執行操作。這就是意圖真正有價值的地方:您可以創建一個描述您想要執行的操作的意圖,並且系統從另一個應用程序啓動相應的Activity。如果有多個Activity可以處理意圖,那麼用戶可以選擇Activity使用哪一個。例如,如果您想允許用戶發送電子郵件,則可以創建以下意向:

Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);

在EXTRA_EMAIL加入額外的意圖是該電子郵件應該發送電子郵件地址的字符串數組。當一個電子郵件應用程序響應這個意圖時,它讀取額外提供的字符串數組,並將它們放在電子郵件組合表單的“to”字段中。在這種情況下,電子郵件應用程序的Activity開始,當用戶完成時,Activity恢復。

startActivityForResult()

有時您想在Activity結束時從Activity中取回結果。例如,您可以開始一項Activity,讓用戶在聯繫人列表中選擇一個人; 當它結束時,它返回被選中的人。爲此,您可以調用 startActivityForResult(Intent, int) 方法,其中integer參數標識調用。此標識符旨在消除startActivityForResult(Intent, int) 來自同一Activity的多個呼叫之間的歧義 。它不是全局標識符,不會與其他應用程序或Activity發生衝突。結果通過您的onActivityResult(int, int, Intent) 方法返回 。Activity

當一個孩子Activity退出時,它可以調用setResult(int)將數據返回給其父代。兒童Activity必須始終提供結果代碼(可以是標準結果 RESULT_CANCELED)RESULT_OK,或者提供任何自定義值開始RESULT_FIRST_USER。另外,子Activity可以選擇返回一個Intent 包含它想要的其他數據的對象。父Activity使用該 onActivityResult(int, int, Intent) 方法以及最初提供的父Activity的整數標識符來接收信息。

如果某個子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));
             } 
         } 
     } 
 } 

協調Activity

當一項Activity開始另一項Activity時,它們都會經歷生命週期轉換。第一個Activity停止操作並進入暫停或停止狀態,而另一個Activity則被創建。如果這些Activity共享保存在光盤或其他地方的數據,重要的是要明白,第一個Activity在創建第二個Activity之前尚未完全停止。相反,啓動第二個過程的過程與停止第一個過程的過程重疊。

生命週期回調的順序已被很好地定義,特別是當兩個Activity處於同一個進程(應用程序)並且一個正在啓動另一個時。以下是Activity A啓動Activity B時發生的操作順序:

  1. Activity A的onPause()方法執行。
  2. Activity B的onCreate(), onStart()和 onResume()方法按順序執行。(Activity B現在有用戶焦點。)
  3. 然後,如果Activity ActivityA在屏幕上不再可見,則onStop()執行其方法。

這種可預測的生命週期回調序列允許您管理從一個Activity到另一個Activity的信息轉換。

Lastest Update:2018.05.18

Activity目錄介紹

聯繫我

QQ:94297366
微信打賞:https://pan.baidu.com/s/1dSBXk3eFZu3mAMkw3xu9KQ

公衆號推薦:

【Android必備】Activity的生命週期(2)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章