ListPreference と % の罠


“%” を含む summary を設定すると不可解なエラーが・・・

Android で設定値を扱う時に利用するクラスが Preference です。中でもリスト形式で設定値を選択するのが ListPreference です。
listpreference
上図のように、ListPreference で “%” という文字を含んだ選択肢を扱う場合には注意が必要です。現在の設定値をユーザに示すためには summary を使うことになりますが、xml 上で android:summary=”20%” としたり、コード上で setSummary(“20%”) とした途端、意味の分からないエラーに悩まされるハメに陥ります。実際に発生するエラーは色々なもので、思いもしないところに発生したりするので原因の特定に時間がかかります。

summary は書式文字列(ただし Honycomb 以降)

原因は、summary が書式文字列として取り扱われることにあります。リファレンスsetSummary メソッドの説明は以下のようになっています。

If the summary has a String formatting marker in it (i.e. “%s” or “%1$s”), then the current entry value will be substituted in its place when it’s retrieved.

もし、summary が書式文字列を含む場合(例: “%s” や “%1$s” 等)、summary の値を取得する際に該当箇所に現在のエントリ値が代入されます。

これにより、 “20%” のような文字列の “%” は書式の開始と受け取られるため不正な書式となり、エラーが発生します。しかも、xml の読み取り時や setSummary の実行時ではなく、summary が表示される段階でエラーが発生するため原因が非常にわかりにくくなります。

このエラーを避けるためには、“%” を表示したい場合には “%%” と指定します。つまり、”20%” と表示するためには setSummary(“20%%”) とします。

書式文字列が使えて自動的に現在値と置き換えられるのは一見便利そうに思えますが、設定を変更した場合に自動的に表示が更新されるわけではなく、OnSharedPreferenceChangeListener の設定は必要なので、手間が省けるわけではありません。

その上やっかいな事に、リファレンスには特に断りがありませんが、書式文字列として扱われるのは Honycomb 以降で、Gingerbread 以下では単なる文字列として扱われます。つまり、setSummary(“20%%”) とすると、Honycomb 以降では “20%” と表示され、Gingerbread 以下では “20%%” と表示されてしまいます。(この事実は、こちらのサイトで知り、実際にエミュレータで確認しました。)

どのように対処するか

対処方法は以下のようになるかと思います。

  1. summary の初期値については、
    プラットフォーム別のリソースファイル(ここでは、pref_default.xml とします) で定義しておきます。

    [values/pref_default.xml]

    [values-v11/pref_default.xml]

    values-v11 で定義された値は、API レベル 11 以上の場合のみ適用されます。従って Gingerbread(API レベル 9, 10)以下と、Honycomb(API レベル 12, 13) 以上とで異なる値を提供できます。この値を利用して、以下のように summary を設定できます。

    [preferences.xml]

  2. また、設定値が変更された時の対処は、
    onSharedPreferenceChanged にて、以下のように Honycomb 以降の場合には “%” を余分に付加するようなコードを書けば良いでしょう。

※2012/02/16 Preference オブジェクトの取得と使用が離れていたので、findPreference を pref 使用の直前に移動しました。

以上で、どのプラットフォームでも ListPreferencesummary を正しく表示できるようになります。
[参考にしたサイト]

Eclipse で Deprecated メソッドの取り消し線を消すには


Android は頻繁にバージョンアップが行われるため、古い API のメソッドが非推奨となり、新しいメソッドが推奨されているケースがよくあります。現在ですと、3.x(Honeycomb) 以降で採用された API が推奨になり、2.x 以下でしか使えないでも使えるメソッドが Deprecated 扱いになっている事がよくあります。

現状、Support Library で対応出来る場合は新しい API を使うのがベストだと思われます。しかし、同ライブラリが対応していない場合は、古い API を使わざるを得えません。(少なくとも Gingerbread は、まだ 50% 近いシェアを持ちます。 詳しくは、Dashboards を参照。)

Eclipse で非推奨の古いメソッドを使用した場合、デフォルトの設定では「取り消し線」が付けられるためコードが読み難くなってしまいます。またこれは、@SuppressWarnings(“deprecation”) を付けても消えません。

「取り消し線」が無くても、以下のように lint が警告マークを付けてくれるので特に困らないと思います。
deprecated_method

そこで、この「取り消し線」を消す設定を調べてみました。

Java 開発(Android 開発を含む)時の、Deprecated に対する「取り消し線」を消すのは、以下のように簡単に行えます。

  1. Window > Preferences > Java > Editor > Syntax Colorling を開く
  2. Element にある “Deprecated members” を選択
  3. Enable のチェックマークをはずす
  4. Apply ボタンを押す

syntax_coloring

あるいは、Enable のままにしておいて、Color を変更するとか、StrikethroughUnderline にするとかでも良いでしょう。もちろん、代替の推奨メソッドが利用できる場合はそちらを利用すべきです。