XMLですべてのレイアウトを定義できますが、「値が変更された」「クリックされた」というリスナーは、コーディングしなければなりません。以下に1つ取り上げてみます。
// チェックボックス設定のインスタンスを、キーを基に取得する CheckBoxPreference cbp = (CheckBoxPreference)findPreference("checkbox_preference"); // リスナーを設定する cbp.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { String summary; if (((Boolean)newValue).booleanValue()) { summary = "Selected"; } else { summary = "Unselected"; } // 更新された値に応じて概要を変更する ((CheckBoxPreference)preference).setSummary(summary); // 変更を適用するために true を返す return true; } });
設定を変更することで、以下のように概要が変化します。
XMLレイアウトで必要なコーディングは、基本的にこのリスナー登録だけです。今回のリスナーは「入力の状態に応じて概要を変更する」のみですが、実際には「入力チェックを行って、不正な入力の際には値を反映させない(falseを返す)」「リングトーン設定であれば、実際にデバイスの設定を変更する」などが行われます。
実際に動作させてみて気が付かれた方がいるかもしれませんが、リスナーは変更時に概要を設定し直すので、画面表示時には状態が分かりません。
このような場合はPreferenceManagerを使用して、現在の設定内容を取得します。PreferenceManagerの使い方は、この後すぐに解説します。
PreferenceActivityで設定された内容は、PreferenceActivityの表示時に自動的に読み込まれますが、設定された内容をアプリ本体で取得する場合は、PreferenceManagerとSharedPreferencesを使用します。
// 【1】デフォルトの SharedPreference を取得する SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); // 【2】設定内容をコミットする sp.edit().commit(); // 【3】設定内容をすべて取得する Map<String, ?> map = sp.getAll(); CharSequence[] list = new CharSequence[map.size()]; int i = 0; for (String key : map.keySet()) { list[i++] = key + "=" + map.get(key); }
【1】では、デフォルトのSharedPreferencesを取得しています。SharedPreferencesは、名前を付けて取得するメソッド「ContextWrapper#getSharedPreferences(String, int)」が用意されていて、このメソッドを使用する場合、以下の呼び出しが同じ動作になります。
getSharedPreferences("com.example.android.preference_preferences", MODE_PRIVATE);
デフォルトのSharedPreferencesの名前は、「パッケージ名_preference」というふうに決まっています。設定を初期化したい場合は、このファイルを削除すれば簡単に実現できます。1つのアプリで複数の設定を使用したい場合は、デフォルトを使用するのではなく、上記メソッドを使用して作成するとよいでしょう。作成する際に、第2引数に、定数「MODE_WORLD_READABLE」「MODE_WORLD_WRITEABLE」を指定してパーミッションをコントロールできます。
【2】では、SharedPreferencesのエディタを取得して、設定内容をコミットしています。SharedPreferencesは、永続化のためにストレージ上にファイルとして保存されますが、保存されるのはアプリが終了するタイミングで、それまではメモリ上に展開されています。ここでcommit()メソッドを呼び出しておくことで、メモリ上で変更された内容をストレージにコミットし、その内容を取得するようにしています。
【3】では、すべての設定項目をMapオブジェクトとして取得しています。個別にキーとデフォルト値を指定して値を取得するgetBoolean()、getFloat()、getInt()、getLong()、getString()が用意されているので、通常はこちらを使用します。
しばしば設定項目には依存関係があるものもあります。例えばWi-Fiを使う場合はアクセスポイントの設定が必要ですが、Wi-Fiを使用しない場合はアクセスポイントの設定は不要です。
今回のアプリでは、以下のように動作します。
このような依存関係もXMLで簡単に定義できます。
【1】↓依存元の設定項目を定義 <CheckBoxPreference android:key="parent_checkbox_preference" android:title="@string/parent_preference_title" android:summary="@string/parent_preference_summary" /> <CheckBoxPreference android:key="child_checkbox_preference" 【2】↓依存元のキーを指定 android:dependency="parent_checkbox_preference" 【3】↓自動的に使用可・使用不可が切り替わるレイアウトを設定 android:layout="?android:attr/preferenceLayoutChild" android:title="@string/child_preference_title" android:summary="@string/child_preference_summary" />
親の設定項目を定義し、子の設定項目のandroid:dependencyに親のキーを、「android:layout」に「?android:attr/preferenceLayoutChild」を指定します。この設定を行うことで、「親がチェックされているときだけ子が使用できる」という動作が実現できます。
これをコーディングで行う場合、以下のようになります。
// 子設定を生成する際にonDependencyChangedをオーバーライド CheckBoxPreference childCheckBoxPref = new CheckBoxPreference(this) { @Override public void onDependencyChanged(Preference dependency, boolean disableDependent) { setEnabled(!disableDependent); } }; setPreferenceScreen(createPreferenceHierarchy()); // setPreferenceScreen が終わってから setDependency() を呼び出し getPreferenceManager().findPreference("child_checkbox_preference").setDependency("parent_checkbox_preference");
本来であれば、setDependency()というメソッドで依存関係を設定できますが、setLayoutResourceで設定するandroid.R.attr.preferenceLayoutChildが正常に機能しないため、期待通りの動作になりません(常に使用可能です)。ApiDemoのオリジナルのソースコードは別の不具合(setKey()が行われていない)がありますが、不具合を修正してもやはり期待通りに動作しません。
Androidのソースコードを検索してsetDependency()を使用している個所を確認したところ、使用しているすべてでXMLレイアウトの補助として使用されていることが分かり、XMLレイアウトで定義したファイルに対してsetDependency()を行ったところ、期待通りの動作になるため、これはもしかするとAndroidの不具合なのかもしれません。
上記の回避方法でも、まったく同様の動作ですが、XMLレイアウトは属性を2つ追加するだけなので、前述したとおりレイアウトはXMLで行うことを強く推奨します。
アプリに設定を持たせたい場合は、ごく簡単なものであればMenuなどでトグル状態を実装するなどの方法がありますが、いずれにせよ設定された値は永続化しなければならないため、その手間を考えるとPreferenceActivityを使うことは良い選択肢といえるでしょう。
次回はアニメーションで華やかな演出を行う方法について解説する予定です。
Copyright © ITmedia, Inc. All Rights Reserved.