チュートリアル - アクティビティの状態を保存する

アクティビティ ライフサイクル ガイドで、状態の保存の根拠となる理論について説明しました。ここでは、例を見てみましょう。

アクティビティ状態のチュートリアル

ActivityLifecycle_Start プロジェクト (ActivityLifecycle サンプル) を開き、ビルドして実行してみましょう。 これは非常にシンプルなプロジェクトで、アクティビティ ライフサイクルとさまざまなライフサイクル メソッドの呼び出し方法を示す 2 つのアクティビティがあります。 アプリケーションを起動すると、次の MainActivity 画面が表示されます。

Activity A screen

状態遷移の表示

このサンプルの各メソッドは、アクティビティの状態を示すために IDE アプリケーション出力ウィンドウに書き込みます。 (Visual Studio で出力ウィンドウを開くには、「CTRL-ALT-O」と入力します。Visual Studio for Mac で出力ウィンドウを開くには、[表示] > [パッド] > [アプリケーション出力] の順にクリックします)。

アプリが最初に起動すると、出力ウィンドウにアクティビティ A の状態の変更が表示されます。

[ActivityLifecycle.MainActivity] Activity A - OnCreate
[ActivityLifecycle.MainActivity] Activity A - OnStart
[ActivityLifecycle.MainActivity] Activity A - OnResume

[アクティビティ B の開始] ボタンをクリックすると、アクティビティ B の状態が変更される間、アクティビティ A が一時停止および停止することがわかります。

[ActivityLifecycle.MainActivity] Activity A - OnPause
[ActivityLifecycle.SecondActivity] Activity B - OnCreate
[ActivityLifecycle.SecondActivity] Activity B - OnStart
[ActivityLifecycle.SecondActivity] Activity B - OnResume
[ActivityLifecycle.MainActivity] Activity A - OnStop

その結果、アクティビティ B が開始され、アクティビティ A の代わりに表示されます。

Activity B screen

[戻る] ボタンをクリックすると、アクティビティ B が破棄され、アクティビティ A が再開されます。

[ActivityLifecycle.SecondActivity] Activity B - OnPause
[ActivityLifecycle.MainActivity] Activity A - OnRestart
[ActivityLifecycle.MainActivity] Activity A - OnStart
[ActivityLifecycle.MainActivity] Activity A - OnResume
[ActivityLifecycle.SecondActivity] Activity B - OnStop
[ActivityLifecycle.SecondActivity] Activity B - OnDestroy

クリック カウンターの追加

次に、クリックされた回数をカウントして表示するボタンが表示されるように、アプリケーションを変更します。 まず、次の MainActivity にインスタンス変数 _counter を追加しましょう。

int _counter = 0;

次に、Resource/layout/Main.axml レイアウト ファイルを編集し、ユーザーがボタンをクリックした回数を表示する新しい clickButton を追加します。 その結果生成される Main.axml は、次のようになります。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <Button
        android:id="@+id/myButton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/mybutton_text" />
    <Button
        android:id="@+id/clickButton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/counterbutton_text" />
</LinearLayout>

MainActivityOnCreate メソッドの末尾に次のコードを追加しましょう。このコードでは、clickButton からクリック イベントを処理します。

var clickbutton = FindViewById<Button> (Resource.Id.clickButton);
clickbutton.Text = Resources.GetString (
    Resource.String.counterbutton_text, _counter);
clickbutton.Click += (object sender, System.EventArgs e) =>
{
    _counter++;
    clickbutton.Text = Resources.GetString (
        Resource.String.counterbutton_text, _counter);
} ;

アプリをビルドしてもう一度実行すると、新しいボタンが表示され、クリックするたびに _counter の値がインクリメントされて表示されます。

Add touch count

ただし、デバイスを横モードに回転すると、このカウントは失われます。

Rotating to landscape sets the count back to zero

アプリケーションの出力を調べると、アクティビティ A が一時停止し、停止し、破棄され、再作成され、再起動された後、縦モードから横モードへの回転中に再開されたことがわかります。

[ActivityLifecycle.MainActivity] Activity A - OnPause
[ActivityLifecycle.MainActivity] Activity A - OnStop
[ActivityLifecycle.MainActivity] Activity A - On Destroy

[ActivityLifecycle.MainActivity] Activity A - OnCreate
[ActivityLifecycle.MainActivity] Activity A - OnStart
[ActivityLifecycle.MainActivity] Activity A - OnResume

アクティビティ A はデバイスの回転時に破棄されて再作成されるため、インスタンスの状態は失われます。 次に、インスタンスの状態を保存して復元するコードを追加します。

インスタンスの状態を保持するコードの追加

インスタンスの状態を保存するメソッドを MainActivity に追加しましょう。 アクティビティ A が破棄される前に、Android は自動的に OnSaveInstanceState を呼び出し、インスタンスの状態を格納するために使用できるバンドルを渡します。 これを使用して、クリック数を整数値として保存しましょう。

protected override void OnSaveInstanceState (Bundle outState)
{
    outState.PutInt ("click_count", _counter);
    Log.Debug(GetType().FullName, "Activity A - Saving instance state");

    // always call the base implementation!
    base.OnSaveInstanceState (outState);    
}

アクティビティ A が再作成されて再開されると、Android はこの BundleOnCreate メソッドに戻します。 OnCreate にコードを追加して、渡された Bundle から _counter の値を復元しましょう。 clickbutton が定義されている行の直前に次のコードを追加します。

if (bundle != null)
{
    _counter = bundle.GetInt ("click_count", 0);
    Log.Debug(GetType().FullName, "Activity A - Recovered instance state");
}

アプリをもう一度ビルドして実行し、2 番目のボタンを数回クリックします。 デバイスを横モードに回転しても、カウントは保持されます。

Rotating the screen shows count of four preserved

出力ウィンドウを確認して、何が起こったかを見てみましょう。

[ActivityLifecycle.MainActivity] Activity A - OnPause
[ActivityLifecycle.MainActivity] Activity A - Saving instance state
[ActivityLifecycle.MainActivity] Activity A - OnStop
[ActivityLifecycle.MainActivity] Activity A - On Destroy

[ActivityLifecycle.MainActivity] Activity A - OnCreate
[ActivityLifecycle.MainActivity] Activity A - Recovered instance state
[ActivityLifecycle.MainActivity] Activity A - OnStart
[ActivityLifecycle.MainActivity] Activity A - OnResume

OnStop メソッドが呼び出される前に、新しい OnSaveInstanceState メソッドが呼び出され、_counter の値が Bundle に保存されます。 Android は OnCreate メソッドを呼び出したときにこの Bundle を戻し、それを使用して _counter の値を元の場所に復元できました。

まとめ

このチュートリアルでは、アクティビティ ライフサイクルに関する知識を使用して状態データを保持しました。