NO_NAME

適当に技術・仕事・ライフハックの話を書いていく予定です。

SharedPreferences にバイナリデータを入れる際にはBase64化が必要

SharedPreferences にバイナリデータを入れる際は Base64.encodeToString(byte, int) を使って文字列化する必要がある。
new String(byte
) を使って文字列化した場合、データを取り出すときになって下記のようなエラーが発行される。

org.xmlpull.v1.XmlPullParserException: Error parsing document. (position:line -1, column -1) caused by: org.apache.harmony.xml.ExpatParser$ParseException: At line 3, column 29: not well-formed (invalid token)

Sony Tablet S をUSBデバッグに接続する

Sony Tablet S は通常のデバッグ用の手続きだけでは Mac では adb に認識されない。
次のようにベンダーIDを adb_usb.ini に書き込むと認識してくれるようになる。

echo "0x54c" >> $HOME/.android/adb_usb.ini

Tablet本体には「USBデバッグが接続されました。」と書いてあるので、紛らわしい。

アプリケーションを終了させる

結論から言うと Android でアプリケーションを終了させる方法は用意されていない。
とはいえいくつか回避策がある。

  • Activity#moveTaskToBack(true) でホームスクリーンに戻ることができる。
    ただし、この場合 Task は破棄されないので、再びこのアプリケーションを開いた際は閉じた画面から開始される。
  • Task の Activity で一つ一つ Activity#finish() をコールする。
    Task の Activity 一覧を取得する方法はないので Activity各自の onPause(...) 等で finish() をコールするしかない。
  • ルートActivity が決まっている場合、 Intent.FLAG_ACTIVITY_CLEAR_TOP フラグをつけ、その Activity を開始する。
    Extras に exitキー を true で追加するなどで終了する旨を表現し、ルートActivity ではその値を見て finish() を実行する。

回避策として使えそうで使えないものもいくつかあるので注意。

  • Activity が一つでも残っている状態で System.exit() を実行する
    エラーやANRダイアログで強制終了されたときのように Task が復元され、終了した Activity から開始される。

ちなみにAndroid でアプリケーションを終了させる方法が用意されていないのは意図的にそう設計されているものでありAndroidの不具合というわけではない。
(それに関しては参考としてあげた StackOverflow の回答二つが秀逸。)

参考

アプリケーションの初期化方法

認証やデータの取得等、アプリケーション起動時に必ず実行したい初期化をどこに入れるのが良いのか調査した。
見つかったパターンは以下の通り。
それぞれ利点・欠点があるのでどれが良いとは一概には言えない。

  1. ApplicationManifest.xml で Main Activity として指定する Activity で初期化
  2. Application#onCreate() で初期化
  3. Application#onCreate() で非同期初期化を開始、その初期化結果が必要な箇所では初期化が終わるまで待機
  4. 全Activity の開始時に初期化されているか否かをチェックするメソッドを用意しておき、そのメソッドが false を返した場合、初期化用 Activity を開始

ApplicationManifest.xml で Main Activity として指定する Activity で初期化

  • 利点
    • 初期化している間、スプラッシュスクリーンを出すなどUIを表示することができる
    • 実装に必要なコードが少ない。
  • 欠点
    • 思いの外、実行されないケースが多い。
      実行されないケースとしては以下のケースがある。
      • 他のアプリケーションから初期化用Activityを通さない形で他のActivityが呼び出されるケース。
      • 他のアプリケーションを実行している間に本アプリケーションのプロセスがリソース削減のために落とされる。
        そしてその後、本アプリケーションに戻ってくるケース。
      • ランチャーから起動した際、Activity Stackが復元され、初期化用Activityを通さず他のActivityから開始されるケース。

Application#onCreate() で初期化

  • 利点
    • プロセス開始時に必ず実行される。
    • 実装に必要なコードが少ない。
  • 欠点
    • スプラッシュスクリーンを含めUIが表示されず、ブラックスクリーンのままになってしまう。

Application#onCreate() で非同期初期化を開始し、その初期化結果が必要な箇所では初期化が終わるまで待機

  • 利点
    • Application実行時に必ず実行される
  • 欠点
    • 初期化結果が必要な箇所すべてに初期化判定コードと初期化が終わるまで待機するコードを入れる必要がある

全Activity の開始時に初期化されているか否かをチェックするメソッドを用意しておき、そのメソッドが false を返した場合、初期化用 Activity を開始

  • 利点
    • Activityが表示される際、必ず初期化済みであることが保証される。
    • 初期化中UIを表示することができる。
  • 欠点
    • 全Activityにコードを入れる必要がある。

Google Chrome でクラッシュせずに印刷を実行する

Google Chrome では印刷を実行すると自動的にプレビュー付きの印刷ページが開かれるが、このプレビュー部分がほとんどの場合クラッシュする。
そうすると印刷に進めなくなってしまう。

ショートカットキー [Option + Command + P] で印刷を実行すると、Mac OS 標準のプリントダイアログに飛ぶのでクラッシュを避けることができる。

この不具合のおかげで楽天トラベルのチケット印刷にかなり手間取った。

OpenSSL で作成した認証局を Subversion へ登録する

~/.subversion/servers へ以下のように認証局を記載する。

ssl-authority-files = /path/to/CAcert.pem;/path/to/CAcert2.pem

Mac OS X 10.5の場合

プリインストールされている Subversion のバージョンが 1.4.4 と古いせいか下記のようなエラーが出てしまった。

$svn info http://host/path
svn: PROPFIND request failed on '/path'
svn: PROPFIND of '/path': Certificate verification error: certificate signature failure (https://host)

MacPortsSubversion 1.7.2 をインストールし、それを利用するように変更したところ問題なく動作するようになった。