やまものブログ

メモ書きブログです (^_^;A

getLastNonConfigurationInstance() の書き換え

今週は、

CHAPTER 06 絵日記アプリを作ろう
を終わらせたかったのですが、力及ばず、
    LESSON 21 絵日記アプリを画面を作ろう
    LESSON 22 投稿画像をサムネイルで表示しよう
だけ実行するところまでとなりました。
この CHAPTER には、さらに、LESSON 23 と 24 があるので、半分ということです


ここでも先週と同様に下記のdeprecated(推奨しない,廃止) を対策しました。
  • constructor CursorAdapter(Context, Cursor)
  • stopManagingCursor(Cursor)
  • managedQuery(Uri, String, String, String, String)

今回、新たに遭遇したのは、下記メソッドの deprecated でした。
  • getLastNonConfigurationInstance()

このメソッドに関しては「10日でおぼえる Androidアプリ開発入門教室」にしっかり解説がありました。一時保存した Activity のデータを取得するメソッドだそうです。それが必要になる状況でありがちなのが「画面回転」だとか。画面を回転させると、Activity は、そのリソースが破棄されて再生成されるので、破棄されたデータを復帰する処理が必要だそうです。この一時保存と復帰の処理をちゃんと記述していないと、画面を回転させると不正終了してしまうとか

サンプルコードでは、
(1) onRetainNonConfigurationInstance() で保存
(2) getLastNonConfigurationInstance で取得処理
という仕組みが使われているのですが、この取得処理のメソッドが deprecated でした

エミュレータ (AVD) で実行しているだけなので画面回転は考えなくていいのですが、とりあえず、deprecate 対策だけはこなしておきたく、Web で断片的に拾い集めた情報をもとに以下のように書き換えてみました。

まず、保存処理 onRetainNonConfigurationInstance() は、
@Override
public Object onRetainNonConfigurationInstance() {
     EditText txtcontent = (EditText) findViewById(R.id.EditText01);
     ViewCache cache = new ViewCache();
     cache.date = mDate;
     cache.contents = txtcontent.getText().toString();
     cache.imgeuri = mSelectImage;
     cache.bmp = (Bitmap) mImageView.getTag();
     return cache;
}

/***
* 回転時の画面データのキャッシュ
*
* @author yokmama
*
*/
private static class ViewCache {
     private long date;
     private String contents;
     private Uri imgeuri;
     private Bitmap bmp;
}
となっていたのを、下記のように onSaveInstanceState() へ変更しました。
@Override
protected void onSaveInstanceState(Bundle outState) {
   EditText txtcontent = (EditText) findViewById(R.id.EditText01);
   outState.putLong("date", mDate);
   outState.putString("contents", txtcontent.getText().toString());
   outState.putParcelable("imgeuri", mSelectImage);
   outState.putParcelable("bmp", (Bitmap) mImageView.getTag());
}

次に、取得処理ですが、onCreate(Bundle savedInstanceState) にて、getLastNonConfigurationInstance() で取得した ViewCache cache を使っていた処理:
ViewCache cache = (ViewCache) getLastNonConfigurationInstance();
if (cache == null) {
<中略>
} else {
     mDate = cache.date;
     String date = Defines.sFmt.format(mDate);
     txtsubject.setText(date);
     txtcontent.setText(cache.contents);
     mImageView.setTag(cache.bmp);
     if (cache.imgeuri != null) {
          mSelectImage = cache.imgeuri;
     }
     if (cache.bmp != null) {
         mImageView.setImageBitmap(cache.bmp);
     }
}
を、下記のように onCreate() の引数 Bundle savedInstanceState を使うように変更しました。
//ViewCache cache = (ViewCache) getLastNonConfigurationInstance();
if (savedInstanceState == null) {
<中略>
} else {
     mDate = savedInstanceState.getLong("date");
     String date = Defines.sFmt.format(mDate);
     txtsubject.setText(date);
     txtcontent.setText(savedInstanceState.getString("contents"));
     Bitmap bmp = savedInstanceState.getParcelable("bmp");
     mImageView.setTag(bmp);
     Uri imgeuri = (Uri) savedInstanceState.get("imgeuri");
     if (imgeuri != null) {
         mSelectImage = imgeuri;
     }
     if (bmp != null) {
         mImageView.setImageBitmap(bmp);
     }
}

エミュレータでの実行では画面回転はしていないため、本当にこれで動くのかどうかは不明ですが、サンプルアプリ「絵日記アプリ(LESSON22時点)」は動作しました。
# この書き換えに問題があればご指摘いただけると幸甚です


下記は、このアプリの動作画面のスクリーンショットです。
イメージ 1

上記は「検索結果」の表示で、他に「検索」と「日記を追加」の機能があります。「日記を追加」では AVD の /mnt/sdcard/ に保存されている画像とコメント(文字)を組にして日記に追加できます。「検索」ではそのコメントをキーワードに検索して、ヒットしたものを上記のように表示できます。


登録する画像ファイルについては、ホスト(Ubuntu)上にある画像ファイルをエミュレータ (AVD) に追加しました。その手順は
Android Virtual Device (AVD) Manager
を起動して、
File Explorer
というタブで、
/storage/sdcard/
を選んで、UbuntuNautilus からドラッグ&ドロップで JPEG ファイルを登録しました


最後に、蛇足ですが、project.properties にて
target=android-11
という設定した(意図せずなっていた)ところ、メソッドの deprecate が消えました。残念ながら、この状態のプロジェクトに対して、API 16用の AVD は起動しませんでした。API 11 用に AVD を作れば動かすことはできそうですが、自分が所持している実デバイスでは使えない可能性が高いので試していません