2013年8月27日火曜日

SQLiteかPreferencesか-ProcessかThreadか

アプリの設定画面ならPreferencesというのがお約束。
そんなwebの情報をちらほら見かける。

が、そんなPreferencesで大丈夫か。

私も設定画面はPreferencesで作るつもりでした。
久々に使うことになったので色々調べてみました。

今時のPreferencesはjsonObjectやArrayListとかつっこめるらしい。すげー
キーだけでやりたい放題じゃまいか。便利便利。

さらに調べる。

どーもPreferencesがきなくさい。
追記:Contextを引数に取る場合のものは全てあやしい。
対策としては全て同じpackageで行うっていうことかな?
この問題はandroidのversionが4.0.3以上だと発生するそうです。
2.xとか早く駆逐されてほしいと切に願います。

何がきなくさいって、commitしたのにcommitできてないとかあるらしい。
より正確に言えば、commitを記述したけど、ちがう値をもってくるというものだった。
設定した値を反映してフラグメントやアクティヴィティで使用するケースがほとんどだ。
OnSharedPreferenceChangeListenerで変更検知というのもあるけど、
処理の重たいもの、もしくは何らかの理由で重たくなった場合、
こちらが期待したとおりの値を取得できるのだろうか。

さらに厄介なことにプロセスやスレッド絡みでも発生する問題がある。
AからPreferencesにアクセス。変更。
BからPreferencesにアクセス。変更。
同じコンテキスとした場合、さてこれはどうなるか。
例えが若干違うような気がしたので追記。
同一プロセス内で複数のアプリの Context を扱う場合、
つまり複数のパッケージのコンテキストで ContextImpl#getSharedPreferences(String name, int mode) を呼んだとき、
より具体的にすると、
アプリの中に複数のpackageがあり、各packageで同一のpreferenceを扱う場合、データの整合性が取れなくなる。ということです。

原因はPreferenceManagerの元、つまりSDKのソースにある。
@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;
            }
        }


そうなるとAsyncQueryHandlerもあやしいな。
public AsyncQueryHandler(ContentResolver cr) {
        super();
        mResolver = new WeakReference<ContentResolver>(cr);
        synchronized (AsyncQueryHandler.class) {
            if (sLooper == null) {
                HandlerThread thread = new HandlerThread("AsyncQueryWorker");
                thread.start();

                sLooper = thread.getLooper();
            }
        }
        mWorkerThreadHandler = createHandler(sLooper);
    }

0 件のコメント:

コメントを投稿