2011年02月25日

[Android] 縦横切り替えとインスタンスの再生成

以前から疑問だったことがありました。
縦向き画面のときと、横向き画面のときでレイアウトを変えたい場合どのようにしたら良いのだろう?と。

当時考えた方法は、とりあえず以下の4点でした。

◆configChangesを無指定にして、Activityが再生成されるようにする場合
1. layout-port、layout-land にxmlを置く。毎回Activityが破棄されるので、それでも問題ない作りにする。

◆configChangesに縦横切り替えをしていしてActivityが再生成されないようにする場合
2. 基本のレイアウトをlayout.xmlで記述する。差異のある部分だけプログラムから変更する。
3. layout-port、layout-land にxmlを置く。切り替え時点でsetContentViewを呼び、Viewのインスタンスだけ再生成させる。
4. 全部プログラムでViewを構築する。

1の場合、縦横を切り換えるだけで、onCreate()〜onDestroy()まで行われるため、もろもろのオブジェクトまで破棄〜再生成せねばならず、あまり良い方法には思えませんでした。
通信によって取得した場合も、どこかに保存するような処理を書かねば、縦横切り替えの度に通信が必要になってしまいます。

2の場合ですが、現状この方法で実装しているアプリがあります。
縦横切替のタイミングで呼ばれるメソッド(onConfigrationChanged())で、縦の場合、横の場合と分岐させてレイアウトを変えています。
ただ、setContentView()などを呼ぶとViewのインスタンスが再生成されてしまうので、それらは呼んでいません。
ViewGroupに対してaddView,removeViewなどして、せっせとレイアウトを変えています。
実際にやってみると(やらなくても?)わかるのですが、これはかなりイケていません。
レイアウトを定義している部分がxmlにもプログラムにもあり、どこを直したら良いのかわからなくなります。
もうこの案は二度と採用しないでしょう。

3の場合ですが、ちょっとこれは採用できませんでした。
今考えれば2よりはるかにマシかと思うのですが、2を採用したのは「改修」のタイミングですでに基盤があったのです。
データをViewそのものが持っているような構造になっていたため、Viewのインスタンスを再生成した場合に再描画するためのコードを書くのが恐ろしく面倒でした。

4の場合、これは面倒すぎてすぐに却下しました。


さて、今ならどれを採用するか。
ついこの間までは「やはり3かなぁ」と考えていましたが、最近見つけた以下の記事で考えを改めました。

http://developer.android.com/intl/ja/resources/articles/faster-screen-orientation-change.html

ここにはActivityが破棄されても、必要なインスタンスを持ち続ける方法が書かれていました。
Androidの正統派の作り方はこれなんじゃないかと思いました。
やっていることは簡単で、onRetainNonConfigurationInstance()をオーバーライドして、持ち続けたいインスタンうを返すだけです。
そのインスタンスを使うとき(onCreateだと思います)は、getLastNonConfigurationInstance()を呼ぶだけです。
これだけでわざわざインスタンスの再生成で悩んだり、Singletonオブジェクトを作ったりする必要が無くなると思いました。

詳しくは上の記事を読んでみてください。
他にも同様に役に立つ記事が多数あるようなので、読みたいと思います。

一応、自分でもサンプルコードを書いてみました。
よろしかったらご確認ください。
RotateTest.zip
タグ:android
posted by t2low at 12:05| Android