Android(X06HT Desire) Activity の状態を一時的に保存する。Activity ライフサイクルの確認。
先日の勉強会で発表のために、Android アプリケーションの開発から公開までしたのだけれど、なにぶん知識と時間不足のため、ちょっと完成度低めだったので、少しずつ改良しながら、さらに野望の実現を目指す。
作成したのは、単語帳アプリケーションなのだが、単語帳のカードを途中までめくったところで端末の方向を切り替えると、最初のページに戻ってしまう。これはいただけない。修正する。
プライベートなプリファレンスをつかって、現在のページを保持させれば良いだろう。
getPreferences(MODE_PRIVATE) で、暗黙で Activity の クラス名をキーとしてgetSharedPreferencesを利用できる
プライベートなプリファレンスを使う例
- @Override
- protected void onPause() {
- Editor editor = getPreferences(MODE_PRIVATE).edit();
- // 現在ページを保存
- editor.putInt(PREF_KEY_CURRENT_PRACTICE, vfCard.getDisplayedChild());
- editor.commit();
- super.onPause();
- }
- @Override
- protected void onResume() {
- int idx = getPreferences(MODE_PRIVATE).getInt(PREF_KEY_CURRENT_PRACTICE, 0);
- // 現在ページを復帰
- if (0 <= idx && idx < vfCard.getChildCount()) {
- vfCard.setDisplayedChild(idx);
- }
- super.onResume();
- }
・・・ が、これがうまくいかない。
Activity のライフサイクルイベントのメソッドをオーバーライドして、ログを仕込んで、なにが起こっているか確認してみる
まずは、アプリケーションを起動し、対象の Activity を呼び出すと、
- 09-02 23:32:43.878: INFO/MyApp(11021): onCreate()
- 09-02 23:32:44.668: INFO/MyApp(11021): onStart()
- 09-02 23:32:44.668: INFO/MyApp(11021): onResume()
onCreate から、onStart()、onResume() を経てActivity 実行中に。ふんふん。リファレンス通り。
そして、画面を横にしてみる。
- 09-02 23:33:05.348: INFO/MyApp(11021): onPause()
- 09-02 23:33:05.348: INFO/MyApp(11021): onStop()
- 09-02 23:33:05.348: INFO/MyApp(11021): onDestroy()
- 09-02 23:33:05.428: INFO/MyApp(11021): onCreate()
- 09-02 23:33:06.358: INFO/MyApp(11021): onStart()
- 09-02 23:33:06.368: INFO/MyApp(11021): onResume()
おおっと、画面を横にした程度なら、onPause() から onResume() のコースを取ってくれても良さそうなものだが、一旦 Destroy までされてしまうようだ。
画面の縦と横では内容が全く異なるはずなので、画面自体の再構築の必要がある。当然と言えば当然か。
毎回 onCreate() も呼ばれてしまうとなると、onCreate() で初期化しようにも、Activity を新規に構築するのか、画面の向きが変わったのか判断つかない。 となると、Acitvity を呼び出すタイミングで、値をクリアする操作をしないといけない。 この場合、Activity プライベートなプリファレンスは使えないので、Activity 間で共有できるプリファレンスを使って書き換えてみる。
共有プリファレンスを使う例
- @Override
- protected void onPause() {
- Editor editor = getSharedPreferences(
- PREF_KEY,
- MODE_WORLD_READABLE | MODE_WORLD_WRITEABLE).edit();
- editor.putInt(PREF_KEY_CURRENT_PRACTICE, vfCard.getDisplayedChild());
- editor.commit();
- super.onPause();
- }
- @Override
- protected void onResume() {
- int idx = getSharedPreferences(PREF_KEY, MODE_WORLD_READABLE | MODE_WORLD_WRITEABLE)
- .getInt(PREF_KEY_CURRENT_PRACTICE, 0);
- if (0 <= idx && idx < vfCard.getChildCount()) {
- vfCard.setDisplayedChild(idx);
- }
- super.onResume();
- }
で、呼び出し元の Activity では、上記 onPause と同様にして、putInt() を利用して、 0 (初期値) をセットすれば、期待したように動くようになった。
よしよし。
・・・ が、ちょっとまった。プリファレンスは永続化される。 しかも自分が想定した利用法では、永続化する必要は全くない。たかだか Activity の一時的な状態を格納するだけに使うのはもったいない(?)のではないか。
Application の サブクラスを作成してそこに保持させる
ようなことを、ちらっとどこかで見たな~2chだったかな~
Activity は 破棄されても、Application は、基本生きているはず。ただ、システムによって、メモリが足りないときとかはKill されるということだったかと。リファレンス見てもそういう感じだ。
なので、Application が 不用意に Kill されても 保持していたいような設定などは、上記プリファレンスを使うことによって保持(永続化)し、まぁ使っている間だけ覚えていればいいや的な状態は、Application のメンバーとして持たせることにする。
Application のサブクラスを作成するのは、単純に、android.app.Application を継承したクラスを作成する。
ただし、それだけでは、そのアプリケーションクラスがメインのアプリケーションだと認識されていないので、AndroidManifest.xml に記述を追記してあげる必要がある。application の android:name に自作クラスを設定する。
- <application android:name="CardroidApplication"
- android:icon="@drawable/icon"
- android:label="@string/app_name"
- :
もしくは、AndroidManifest.xml の設定画面、Application タブから、Name を設定する。
また一歩野望に近づいた。