端末の向きを変えれば、アプリも回転したりしなかったりします。回転させないのであれば、特に気にすることはなく、終了。
だけど、回転させたい場合には、それなりの対応をしなければなりません。フォームのデザインを、縦用と横用とを用意するのはもちろん、最低限必要なことです。アプリケーションによっては、それで対応完了する場合もあります。
厄介なのはそれで終わらない場合......内部データの保持が必要な場合なのです。
画面の回転が起こると、Activity は一旦破棄され、然る後に、新しい向きに合わせてActivityが生成され、アプリの実行が再開されます。
Activityは、アプリケーションの本体といってもいい存在ですので、これが破棄されると、内部データも全て破棄されてしまいます。ストップウォッチならば、動作中の状態、ラップタイムのログなどといったデータが全て失われてしまいます。
これを防ぐ方法は色々あるのですが、一応、推奨されている方法は、onSaveInstanceState()と、onRestoreInstanceState()を@Overrideして、必要な情報を、Bundleに保存しBundleから復帰させることです。
単純なデータ型の保存・復帰は Bundle.putInt(i) とか i = Bundle.getInt()とかすればいいので、問題は無いのですが、ややこしいのは、ListViewのデータのようなものたちです。
こういったデータは、SerializableやParcelable でなければなりません。リストであるなら、ParcelableなArrayListである必要があります。Budle は、getParcelableArrayList()/putParcelableArrayList()という機能を持っているからです。
がさがさと、このあたりの情報をググって漁ってくると、Bundle.putSerializable(key, (Serializable)list); list = (List<T>)Bundle.getSerializable(key);でOKみたいなことが書いてあって、画面の回転だけだったら確かにそれで動くのですが、Eclipseは、検証もしないでList<T>型にキャストして良いのかよ?とか警告出しているし、実際に、動作中に、HOMEボタンを押すなどして、ActivityがonPause()を起こすと、Pacelの例外を出して死んでしまいます。
これを避けるためには、ListはArrayListに、要素クラスであるTは、Parcelableにしてやる必要があります。クラスをParcelableにするのは、簡単です。
public class LaptimeListItem implements Parcelable {
public int lap;
public long time;
public long elapsed;
public LaptimeListItem()
{
lap = 0;
time = 0;
elapsed = 0;
}
private LaptimeListItem(Parcel source)
{
lap = source.readInt();
time = source.readLong();
elapsed = source.readLong();
}
public static final Parcelable.Creator<LaptimeListItem> CREATOR = new Parcelable.Creator<LaptimeListItem>() {@Override
public LaptimeListItem createFromParcel(Parcel source) {
// TODO 自動生成されたメソッド・スタブ
return new LaptimeListItem(source);
}@Override
public LaptimeListItem[] newArray(int size) {
// TODO 自動生成されたメソッド・スタブ
return new LaptimeListItem[size];
}
};
@Override
public int describeContents() {
// TODO 自動生成されたメソッド・スタブ
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
// TODO 自動生成されたメソッド・スタブ
dest.writeInt(lap);
dest.writeLong(time);
dest.writeLong(elapsed);
}}
これは、実際に、ラップタイムを保持しているクラスですが、implements Parcelable を宣言に追加して、describeContents()とwriteToParcel()のうち、writeToParcel()の方で、保存すべきメンバをParcelに詰め込みます。
これだけでは、不十分で、public static final Parcelable.Creator<T>() CREATOR というメンバを作成し、createFromParcel()とnewArray()で、それぞれ、new T(source)とnew T[size] を返すようにします。
さらに、createFromParcel()が必要とするので、コンストラクタ T(Parcel source)を作り、その中で、writeToParcel()で詰め込んだ順で、Parcelから取り出して、クラスのメンバにセットします。
ここまで作ってやっておけば、Bundle.putParcelableArrayList(key, list)とlist = Bundle.getParcelableArrayList(key)で、データの受け渡しを、クラッシュすることなく行うことができます。もちろん、Eclipseも文句を言わなくなります。大したことしていないアプリでも、これだけ面倒な処理が必要なのです。とほほ。
コメント