[Android]画面回転によるアクティビティ破棄時にメンバ変数の値を退避させる

投稿者:

以前、こちらの記事で、画面を回転させるとアクティビティやダイアログが一旦破棄されて、再作成されることに触れた。この時アクティビティのメンバ変数はすべて初期化されてしまう。これを確かめてみよう。

次のアプリはボタンをクリックする毎に数字が1ずつ増加していくアプリである

レイアウトファイル
activity_main.xml
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button_increment"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:text="+1"/>

    <TextView
        android:id="@+id/textCounter"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="0"
        android:textSize="40sp"
        android:layout_centerInParent="true"/>

</RelativeLayout>
JAVAファイル
MainActivity.java
public class MainActivity extends AppCompatActivity {
    int mCounter = 0;  //カウンターの値

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final TextView textView = (TextView) findViewById(R.id.textCounter);

        textView.setText(String.valueOf(mCounter));

        Button button = (Button)findViewById(R.id.button_increment);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mCounter++ ;
                textView.setText(String.valueOf(mCounter));
            }
        });
    }
}

アプリを起動すると「+1」ボタンと数値「0」が表示され、ボタンをクリックすると数が1増加する。押せば押すほど数値は増えていく。この数値はMainActivityクラスのメンバ変数mCounterが保持している。

起動直後の状態
「+1」ボタンをクリックすると数字が増えていく

ある程度数値を増やし、画面の向きを変えてみると……

画面の向きを変えた

0に戻ってしまった。
回転によってアクティビティが破棄されて再作成された影響だ。

画面回転後も継続して変数の値を利用する場合、変数の中身をどこかに退避しなければならない。

やり方は難しくはない。アクティビティが破棄されるとき、onDestroyの前にonSaveInstanceState(Bundle outState)が呼ばれるので、これをオーバーライドして引数のBundleにメンバ変数の値を追加する。

退避させた値は再作成時のonCreateメソッドの引数savedInstanceStateにそのまま格納されてくるので、getIntメソッド等で取り出すことができる。savedInstanceStateは初めてインスタンスが作成されたときはnullになっているため、nullかどうかチェックすれば再作成なのかそうでないのかを判別することができる。

修正後のJAVAファイル(レイアウトは省略)
MainActivity.java
public class MainActivity extends AppCompatActivity {
    int mCounter = 0;  //カウンターの値

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final TextView textView = (TextView) findViewById(R.id.textCounter);

        if (savedInstanceState!=null) {
            //savedInstanceStateがnullでないときは
            //オブジェクトが再作成されたと判断
            //カウンターの値を復元
            mCounter = savedInstanceState.getInt("MY_COUNTER");
        }
        textView.setText(String.valueOf(mCounter));


        Button button = (Button)findViewById(R.id.button_increment);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mCounter++ ;
                textView.setText(String.valueOf(mCounter));
            }
        });
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        //メンバ変数mCounterを退避
        outState.putInt("MY_COUNTER", mCounter);
    }
}

これで回転によって変数が初期化されても、savedInstanceStateから値が復元され、継続して値を使うことができる。

向きが変わっても値が保持される

intやString等の基本的な型の変数はこのように値を退避、復元すればよい。
独自クラスを退避させたい場合は、その独自クラスにParcelableインターフェイス実装してputParcelableメソッドでBundleに追加する。Parcelableインターフェイスについてはこちらで簡単に解説しているので見て欲しい。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください