Android(X06HT Desire) Activity の状態を一時的に保存する。Activity ライフサイクルの確認。

先日の勉強会で発表のために、Android アプリケーションの開発から公開までしたのだけれど、なにぶん知識と時間不足のため、ちょっと完成度低めだったので、少しずつ改良しながら、さらに野望の実現を目指す。

作成したのは、単語帳アプリケーションなのだが、単語帳のカードを途中までめくったところで端末の方向を切り替えると、最初のページに戻ってしまう。これはいただけない。修正する。

プライベートなプリファレンスをつかって、現在のページを保持させれば良いだろう。

getPreferences(MODE_PRIVATE) で、暗黙で Activity の クラス名をキーとしてgetSharedPreferencesを利用できる

プライベートなプリファレンスを使う例

  1. @Override
  2. protected void onPause() {
  3. Editor editor = getPreferences(MODE_PRIVATE).edit();
  4. // 現在ページを保存
  5. editor.putInt(PREF_KEY_CURRENT_PRACTICE, vfCard.getDisplayedChild());
  6. editor.commit();
  7. super.onPause();
  8. }
  9. @Override
  10. protected void onResume() {
  11. int idx = getPreferences(MODE_PRIVATE).getInt(PREF_KEY_CURRENT_PRACTICE, 0);
  12. // 現在ページを復帰
  13. if (0 <= idx && idx < vfCard.getChildCount()) {
  14. vfCard.setDisplayedChild(idx);
  15. }
  16. super.onResume();
  17. }

 

・・・ が、これがうまくいかない。

Activity のライフサイクルイベントのメソッドをオーバーライドして、ログを仕込んで、なにが起こっているか確認してみる

まずは、アプリケーションを起動し、対象の Activity を呼び出すと、

android_activity01 

  1. 09-02 23:32:43.878: INFO/MyApp(11021): onCreate()
  2. 09-02 23:32:44.668: INFO/MyApp(11021): onStart()
  3. 09-02 23:32:44.668: INFO/MyApp(11021): onResume()

onCreate から、onStart()、onResume() を経てActivity 実行中に。ふんふん。リファレンス通り。

 activity01

そして、画面を横にしてみる。

android_activity02

  1. 09-02 23:33:05.348: INFO/MyApp(11021): onPause()
  2. 09-02 23:33:05.348: INFO/MyApp(11021): onStop()
  3. 09-02 23:33:05.348: INFO/MyApp(11021): onDestroy()
  4. 09-02 23:33:05.428: INFO/MyApp(11021): onCreate()
  5. 09-02 23:33:06.358: INFO/MyApp(11021): onStart()
  6. 09-02 23:33:06.368: INFO/MyApp(11021): onResume()

activity02

おおっと、画面を横にした程度なら、onPause() から onResume() のコースを取ってくれても良さそうなものだが、一旦 Destroy までされてしまうようだ。

画面の縦と横では内容が全く異なるはずなので、画面自体の再構築の必要がある。当然と言えば当然か。

毎回 onCreate() も呼ばれてしまうとなると、onCreate() で初期化しようにも、Activity を新規に構築するのか、画面の向きが変わったのか判断つかない。 となると、Acitvity を呼び出すタイミングで、値をクリアする操作をしないといけない。 この場合、Activity プライベートなプリファレンスは使えないので、Activity 間で共有できるプリファレンスを使って書き換えてみる。

共有プリファレンスを使う例

  1. @Override
  2. protected void onPause() {
  3. Editor editor = getSharedPreferences(
  4. PREF_KEY,
  5. MODE_WORLD_READABLE | MODE_WORLD_WRITEABLE).edit();
  6. editor.putInt(PREF_KEY_CURRENT_PRACTICE, vfCard.getDisplayedChild());
  7. editor.commit();
  8. super.onPause();
  9. }
  10.  
  11. @Override
  12. protected void onResume() {
  13. int idx = getSharedPreferences(PREF_KEY, MODE_WORLD_READABLE | MODE_WORLD_WRITEABLE)
  14. .getInt(PREF_KEY_CURRENT_PRACTICE, 0);
  15. if (0 <= idx && idx < vfCard.getChildCount()) {
  16. vfCard.setDisplayedChild(idx);
  17. }
  18. super.onResume();
  19. }

で、呼び出し元の Activity では、上記 onPause と同様にして、putInt() を利用して、 0 (初期値) をセットすれば、期待したように動くようになった。

よしよし。

 

・・・ が、ちょっとまった。プリファレンスは永続化される。 しかも自分が想定した利用法では、永続化する必要は全くない。たかだか Activity の一時的な状態を格納するだけに使うのはもったいない(?)のではないか。

 

Application の サブクラスを作成してそこに保持させる

ようなことを、ちらっとどこかで見たな~2chだったかな~

Activity は 破棄されても、Application は、基本生きているはず。ただ、システムによって、メモリが足りないときとかはKill されるということだったかと。リファレンス見てもそういう感じだ。

なので、Application が 不用意に Kill されても 保持していたいような設定などは、上記プリファレンスを使うことによって保持(永続化)し、まぁ使っている間だけ覚えていればいいや的な状態は、Application のメンバーとして持たせることにする。

Application のサブクラスを作成するのは、単純に、android.app.Application を継承したクラスを作成する。

ただし、それだけでは、そのアプリケーションクラスがメインのアプリケーションだと認識されていないので、AndroidManifest.xml に記述を追記してあげる必要がある。application の android:name に自作クラスを設定する。

  1. <application android:name="CardroidApplication"
  2. android:icon="@drawable/icon"
  3. android:label="@string/app_name"
  4. :

もしくは、AndroidManifest.xml の設定画面、Application タブから、Name を設定する。

android_application

また一歩野望に近づいた。

Follow me!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です