その煩雑さを解消するクラスを作った。今の所、この方法がベストな方法だと思う。
Retain.java
以下、Activityの再生成に関する典型的な対処法とその問題点。
Activityの再生成のパターンは2つある
Activityは、以下の場合に再生成される。
- Configuration changeの時(画面の回転など)。プロセスは生きたまま。
- バックグラウンドにいる間にOSによってプロセスごと殺された後、アプリに戻ってきた時。
方法1. onSaveInstanceStateでbundleに入れる
- processが死んでいた場合でも、データが残っている。
- Bundleに入る型しか保持できない(Integer, Boolean, String, Serializableなど)。
例えば、通信処理スレッドを再生成後のinstanceに引き渡す、ということは直接はできない。
- onSaveInstanceState()が呼ばれた後には、もうbundleに入れることができない。
方法2. staticな領域に覚えておく
- processが死んでいない場合は、データは残っている。
- processが死んでいた場合は、データは残っていない。
- Activityが2つ存在するときに、間違って別のActivityにデータを渡さないようにしなくてはならない。
方法3. retain用のFragmentを使う
setRetainInstance(true)なFragmentを用意して、そのretain用Fragmentにデータを覚えさせておく方法。 http://developer.android.com/guide/topics/resources/runtime-changes.html- processが死んでいない場合は、データは残っている。
- processが死んでいた場合は、データは残っていない。
- Activityに紐付いたデータ(ThreadにおけるThread Local Storageのように)なので、別のActivityに間違ってデータを渡してしまうことはない。
- Activityがいなくなると、自動でFragmentも消してくれる。
- あくまでActivityに結びついた情報なので、Activityに含まれるFragmentごとに別々のretain用fragmentをもたせる、と言ったことは非常にしにくい。
- retain用Fragmentを削除するタイミングが難しい。下手なタイミングでFragmentTransactionをすると、IllegalStateExceptionが出る。
- FragmentActivity, Fragmentを使わなくてはならない。
- コードが読みにくい
解決方法
- processが死んだ場合でも、できるだけ情報を残したい、
- でも、bundleに入る情報以外も保持したい
- 3の方法は嫌だ
使い方
private Retain<somedata> retain; // SomeDataは、ParcelableまたはSerializableであること @Override protected void onCreate(Bundle savedInstanceState) { retain = Retain.forSerializable() someData = retain.onCreate(savedInstanceState); if (someData == null) { someData = new SomeData() } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); retain.onSaveInstanceState(outState, someData); } @Override protected void onDestroy() { super.onDestroy(); retain.onDestroy(this); }
これだけで、someDataの情報はできるだけ保持されるし、画面回転等にも対処できる。
0 件のコメント:
コメントを投稿