2012年6月16日土曜日

振る舞いのよいAndroidアプリのために。BundleSaver。


Androidで、Bundleへの保存/復元を自動で行ってくれるユーティリティをつくりました。
GitHub / monochromegane / BundleSaver

2012/07/08
BundleSaverのバージョンアップと使用手順の変更を行いました。
下記ページもあわせてご覧ください。
続・振る舞いのよいAndroidアプリのために。StateSaver。



今回のアジェンダです。
  1. Bundleってなぁに?
  2. Bundleの問題点
  3. BundleSaverで解決

  1. Bundleってなぁに?

AndroidのActivityにはライフサイクルがあります。
別のアプリが前面に来るなどして、バックグラウンドにまわった後、他のアプリによってメモリが不足した場合にActivityが破棄されることがあります。
このとき、メモリ上にだけ展開されていたインスタンス変数などの値も破棄されてしまいます。

再度呼び出されるときは、もう一度Activityを生成しなおすため、前回の状態は失われています。
ユーザ側の立場に立ったとき、前回と同じ状態になるよう復元する必要があります。
このとき、状態を保存、復元する入り口としてAndroidが準備してくれているのがBundleです。

実装方法などは、以下にわかりやすくまとまっています。
Y.A.M の 雑記帳 / Android Bundle で状態を保存


  2. Bundleの問題点

Bundleは実装内容は決まりきっているわりに、インスタンス変数といったアプリ開発中に随時変わっていくところを対象としているので、めんどくさくなってついつい変数との整合性をあわせるのを後回しにしがちです。

保存する必要がある新しい変数つくると、それに応じたreadする処理、writeする処理を書かなくてはならないというのが問題だと思います。

  3. BundleSaverで解決

BundleSaverは、変数の宣言時にアノテーションでBundle対象であることを記載するだけで、保存、復元は自動で行ってくれるユーティリティです。

こんな感じで使います。


対象となる型は、Bundleに格納できるもの + α です。
プリミティブ型、ラッパーオブジェクト、Bundle, Parcelable, Serializable などが格納できます。
詳しくはGitHub上のREADMEをご覧ください。

実装としては、対象のActivityに対して、BundleTargetアノテーションが設定されているインスタンス変数をリクレクションで取得、変数名からキーを生成してBundleへ格納。
復元時は、その逆を行うといった感じです。

対象となるインスタンス変数にアノテーションをつけるだけで、保存/復元処理はBundleSaverを呼ぶだけなので、使いやすくなるんじゃないかと思います。
状態の保存/復元は地味ですが、ユーザ側にとって振る舞いのよいアプリケーションをつくるのに重要な処理なので、ぜひ使ってみてください。

-------------------------
ここはこうした方がよいよとかご指摘ありましたら、教えてもらえれば幸いです。
ではでは。



4 件のコメント:

  1. ものすごいです。これは便利!
    ところで enum・・・今は普通に
    outState.putString("hoge", hoge.name());
    で書き込んで
    hoge = Hoge.valueOf(savedInstanceState.getString("hoge"));
    で読んでますけど、上手い考えございますでしょうか?

    返信削除
  2. コメントありがとうございます。

    ご質問のEnumについて、name()やordinal()を使うこともできますが、そもそもSerializableなオブジェクトとみなすことができますので、
    outState.putSerializable("hoge", hoge);
    で書き込んで
    hoge = (Hoge)(savedInstanceState.getSerializable("hoge"));
    と取得、Enumの型でキャストしてあげるとよいのではないでしょうか。

    また、BundleSaverでもEnum利用できることも確認しましたのでよければご参考ください。

    返信削除
    返信
    1. すみません、私の確認ミスでした。Enum も使えました。最高です!
      それとおっしゃるとおり outState.putSerializable のほうが美しいですね。ありがとうございます。もっとも今後は BundleSaver に頼りっきりになると思いますが(笑)

      私は Matrix をよく使うので早速改造しました。本当に便利です。

      削除
    2. いえいえ、こちらこそコメントいただきありがとうございます。
      また、色々つくってみるのでよろしくお願いします。

      削除