Windows Phone の WebException のハンドリング

Windows Phone の WebRequest で リクエストを送った際にネットワークやサーバ由来のエラーがあると WebException 例外が発生するんですが、この例外のStatusプロパティやResponseプロパティにはクセがあって以下のような現象が発生します。

  • 存在するサーバの、存在しないリソースをリクエストすると、例外のStatusはWebExceptionStatus.UnknownErrorだったり WebExceptionStatus.ProtocolError だったりする。例外のResponse にはサーバからの404レスポンスが正しく格納されている。
  • 接続できないサーバの、存在しないリソースをリクエストすると、例外のStatusはWebExceptionStatus.UnknownErrorになる。例外のResponse には適当にでっち上げられた404レスポンスが格納されている。

サーバに接続できてもいないのに適当にレスポンスをでっち上げるという実装ポリシーも関心しませんが、そのレスポンスのステータスが404だというのも関心しません。接続できないという現象は別に永続的なものではないはずです。

実際、このレスポンスをそのまま信用すると、呼び出し側としては接続のリトライを早急に諦めるか、サーバが404を返しているにも関わらずリトライを続けることになってしまいます。

続きを読む

Windows Phone アプリのUIレイアウトXAMLから文字列リソースを参照する

普通アプリを書く時は端末の言語設定によってテキストリソースを切り替えられるようにする訳ですが、Windows Phone 7.1 SDK でそれをやるのに多少苦労したのでメモしておきます。

もっといい方法を御存知の方は是非教えて下さい。

続きを読む

SharedPreferences と MODE_MULTI_PROCESS がイマイチよろしくない件

運悪くAndroidで複数プロセスのアプリを作ったり、アプリ間で SharedPreferences を相互参照するハメになってしまった場合に役に立つ…いや、たぶん立たないメモ。

Context#MODE_MULTI_PROCESS フラグはどのように使われているか

このフラグはContext#getSharedPreferences(String name, int mode) の第二引数に設定するもので、API Level 11で設定された。Context  |  Android Developersではこう説明されている。

SharedPreference loading flag: when set, the file on disk will be checked for modification even if the shared preferences instance is already loaded in this process. This behavior is sometimes desired in cases where the application has multiple processes, all writing to the same SharedPreferences file. Generally there are better forms of communication between processes, though.

This was the legacy (but undocumented) behavior in and before Gingerbread (Android 2.3) and this flag is implied when targetting such releases. For applications targetting SDK versions greater than Android 2.3, this flag must be explicitly set if desired.

実際にこのフラグが参照されているのは ContextImpl#getSharedPreferences(String name, int mode) の中だけだ。他の箇所では一切参照されていない。

  @Override
    public SharedPreferences getSharedPreferences(String name, int mode) {
        SharedPreferencesImpl sp;
        synchronized (sSharedPrefs) {
            sp = sSharedPrefs.get(name);
            if (sp == null) {
                File prefsFile = getSharedPrefsFile(name);
                sp = new SharedPreferencesImpl(prefsFile, mode);
                sSharedPrefs.put(name, sp);
                return sp;
            }
        }
        if ((mode & Context.MODE_MULTI_PROCESS) != 0 ||
            getApplicationInfo().targetSdkVersion < android.os.Build.VERSION_CODES.HONEYCOMB) {
            // If somebody else (some other process) changed the prefs
            // file behind our back, we reload it. This has been the
            // historical (if undocumented) behavior.
            sp.startReloadIfChangedUnexpectedly();
        }
        return sp;
    }

SharedPreferencesImpl#startReloadIfChangedUnexpectedly は内部で hasFileChangedUnexpectedly() を呼び出していて、そこでは前回から自分が書き込みを行ったかどうか確認したり、ファイルのmtimeとsize が前回ロードしたものと同じかどうか確認したりしている。

まとめるど、このフラグは「getSharedPreferences を呼び出した時にmtimeとsizeを見て適当にロードし直す」というものだ。他の効果は一切ないし、自プロセスが書き込みを行なっていた場合もロードし直さないし、単に0を1に変えるような変更を前回のロードから1秒未満に行った場合もロードし直さない。端末の時計が補正された場合なんかもきっとうまくないケースがあるだろう。穴だらけとしか思えない実装なのだが、今後改善される可能性もあるのでフラグの存在自体は尊重するべきかもしれない。

ついでに言うと、もしあなたが取得した SharedPreferences をどこかクラス内のフィールドに保存しているのなら、それは再利用の際に別プロセスからのアクセスをチェックしていないまずいコードだということになる。

…困ったことに、PreferenceManager がまさにそういう実装になっている。

嫌な汗が流れてきたが、まだ話は終わらない。

では PreferenceManager を使っていないアプリでは MODE_MULTI_PROCESS をちゃんと設定して、かつ頻繁にgetSharedPreferencesを呼び出していれば問題はないのかというと、そんなことはなかった。

続きを読む

Androidアプリからのファイルパーミッションの制御

アプリ間のファイルアクセスの許可/禁止には unix のファイルパーミッションの仕組みが使われています。

Androidではアプリごとにuidとgidが割り当てられていて、パーミッションのうち、otherのread,write,execute ビットを変更することで他アプリからのアクセスを許可/禁止することができます。

パーミッションの設定はネイティブコードならchmod(2)を使うんですが、Javaからだとそのまま呼び出せるようにはなっていません。

そこで今回はアプリからファイルパーミッションを制御するにはどのようなAPIを使えばよいか確認してみます。

続きを読む

Windows Live ID が停止されてる件でたらいまわし続行中

  • SkyDrive Explorerで手持ちの画像を3GBくらいupしてみる
  • 原因はわからないがアカウント停止される
  • Webからサインインできない
  • カスタマー サポートにお問い合わせください。 いくつかの質問をさせていただき、お客様のアカウントが安全であるかをご確認いたします。」
  • MSKKのサイトで問い合わせ先は「Windows Live はコミュニティでのサポートをご利用ください。」
  • Windows Live Solution Center はサインインしないと使用できない
  • 別件でMSの人と話したら「別のメールアドレスでLive IDを作って問い合わせるといいよ」
  • フォーラムに投稿したら「SkyDriveの迷惑行為」の投稿先を伝えられる
  • SkyDriveの迷惑行為 のフォームに書いたら
現在、当サポート窓口では、サーバー側にて問題が発生しているとの
報告を受けておりませんため、本件につきましては、恐れ入りますが、
担当部署に報告し、確認をさせていただきたく存じます。

…どこまで続くんだコレ