以前、こちらの記事で、画面を回転させるとアクティビティやダイアログが一旦破棄されて、再作成されることに触れた。この時アクティビティのメンバ変数はすべて初期化されてしまう。これを確かめてみよう。
次のアプリはボタンをクリックする毎に数字が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が保持している。
ある程度数値を増やし、画面の向きを変えてみると……
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インターフェイスについてはこちらで簡単に解説しているので見て欲しい。