このドキュメントの内容
- 概要
- XML にプリファレンスを定義する
- プリファレンス アクティビティを作成する
- プリファレンス フラグメントを使用する
- デフォルト値を設定する
- プリファレンス ヘッダーを使用する
- プリファレンスを読み込む
- ネットワークの使用を管理する
- カスタム プリファレンスを作成する
キークラス
関連ドキュメント
多くの場合、アプリケーションには、ユーザーがアプリの機能や動作を変更できる設定が含まれています。たとえば、一部のアプリでは、通知を有効にするかどうかや、アプリケーションがクラウドとデータを同期する頻度を、ユーザーが指定できます。
アプリに設定機能を提供するには、Android の Preference API を使用して、他の Android アプリ(システム設定を含む)の操作と整合性のあるインターフェースを構築する必要があります。
このドキュメントでは、Preference API を使用して、アプリの設定機能を構築する方法について説明します。
設定の設計
設定の設計方法については、設定のデザインガイドをご覧ください。
図 1. Android SMS アプリの設定のスクリーンショット。
Preference で定義されたアイテムを選択すると、設定を変更するためのインターフェースが表示されます。
概要
設定は、View オブジェクトを使用してユーザー インターフェースを作成する方法ではなく、XML ファイルで宣言された Preference クラスの各種のサブクラスを使用する方法で作成されます。
1 つの Preference オブジェクトが、1 つの設定の構成要素になります。
各 Preference はアイテムとしてリストに表示され、ユーザーが設定を変更するための適切な UI を提供します。
たとえば、CheckBoxPreference はチェックボックスを表示するリストアイテムを作成し、ListPreference は、選択リスト付きのダイアログを開くアイテムを作成します。
追加した各 Preference は、アプリの設定のためのデフォルトの SharedPreferences ファイルに設定を保存するためにシステムが使用する対応するキーと値のペアを持ちます。
ユーザーが設定を変更する場合、システムが SharedPreferences ファイルの対応する値を更新します。
関連する SharedPreferences ファイルを直接操作することが必要なのは、ユーザーの設定に基づいてアプリの動作を決定するために値を読み込むことが必要な場合のみです。
各設定の SharedPreferences に保存される値のデータ型は、次のいずれかにすることができます。
- Boolean 型
- Float
- Int
- Long
- 文字列
- String
Set
アプリの設定の UI は View オブジェクトではなく Preference で作成されているため、リストの設定を表示するには、専用の Activity サブクラスまたは Fragment サブクラスを使用する必要があります。
- アプリが 3.0 よりも前のバージョンの Android(API レベル 10 以下)をサポートしている場合は、
PreferenceActivityクラスを継承してアクティビティを作成する必要があります。 - Android 3.0 以降では、代わりに、アプリの設定を表示する
PreferenceFragmentをホストする従来のActivityを使用します。ただし、設定のグループが複数ある場合は、PreferenceActivityを使用して大きな画面用の 2 ペイン レイアウトを作成することもできます。
PreferenceActivity と PreferenceFragment のインスタンスの設定方法は、プリファレンス アクティビティを作成するとプリファレンス フラグメントを使用するのセクションをご覧ください。
プリファレンス
アプリの各設定は、Preference クラスの個々のサブクラスに相当します。各サブクラスには、設定のタイトルやデフォルト値などを指定できる一連の核となるプロパティが含まれています。
また、各サブクラスは、専用のプロパティとユーザー インターフェースを提供しています。
たとえば、図 1. は、SMS アプリの設定のスクリーンショットです。
設定画面の各リスト アイテムは、それぞれ異なる Preference オブジェクトに基づいています。
以下は、最も一般的なプリファレンスの一部です。
CheckBoxPreference- 有効または無効にする設定のチェックボックス付きのアイテムを表示します。保存される値は、Boolean です(オンの場合、
true)。 ListPreference- ラジオボタンのリスト付きのダイアログを開きます。保存される値は、サポートされるデータ型(上記参照)であればどのデータ型にもできます。
EditTextPreferenceEditTextウィジェット付きのダイアログを開きます。保存される値は、Stringです。
その他のサブクラスと対応するプロパティについては、Preference クラスをご覧ください。
もちろん、組み込みのクラスがすべてのニーズを満たすわけではなく、アプリケーションがより特殊な機能を必要とする可能性もあります。
たとえば、プラットフォームは、現時点では、数字や日付を選択するための Preference クラスを提供していません。そのため、独自の Preference サブクラスを定義することが必要になる場合もあります。
詳細については、カスタム プリファレンスを作成するセクションをご覧ください。
XML にプリファレンスを定義する
実行時に新しい Preference オブジェクトのインスタンスを作成することもできますが、Preference オブジェクトの階層で XML に設定のリストを定義する必要があります。
XML ファイルは更新が容易な簡単に読むことができる構造を持つため XML ファイルを使用して設定のコレクションを定義することをお勧めします。
また、アプリの設定は通常、事前設定されていますが、設定のコレクションを実行時に変更することもできます。
各 Preference サブクラスは、<CheckBoxPreference> などのクラス名と一致する XML 要素で定義できます。
この XML ファイルは、res/xml/ ディレクトリに保存する必要があります。この XML ファイルには好きな名前を付けることができますが、一般的には、preferences.xml という名前が使用されています。
階層の分岐(この分岐がそれ自身の設定のリストを開きます)が PreferenceScreen のネストされたインスタンスを使用して宣言されているため、必要なファイルは通常 1 ファイルのみです。
注: 複数ペイン レイアウトの設定を作成する場合は、フラグメントごとに別々の XML ファイルが必要です。
XML ファイルのルートノードは、<PreferenceScreen>
Preference を追加します。<PreferenceScreen> 要素内に追加したそれぞれの子は、設定のリストで 1 つのアイテムとして表示されます。
次に例を示します。
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBoxPreference
android:key="pref_sync"
android:title="@string/pref_sync"
android:summary="@string/pref_sync_summ"
android:defaultValue="true" />
<ListPreference
android:dependency="pref_sync"
android:key="pref_syncConnectionType"
android:title="@string/pref_syncConnectionType"
android:dialogTitle="@string/pref_syncConnectionType"
android:entries="@array/pref_syncConnectionTypes_entries"
android:entryValues="@array/pref_syncConnectionTypes_values"
android:defaultValue="@string/pref_syncConnectionTypes_default" />
</PreferenceScreen>
この例には、CheckBoxPreference と ListPreference が含まれています。どちらのアイテムにも次の 3 つの属性が含まれています。
android:key- この属性は、データ値を保持するプリファレンスで必要です。設定の値を
SharedPreferencesに保存するときにシステムが使用する一意のキー(文字列)を指定します。プリファレンスが
PreferenceCategoryまたはPreferenceScreenの場合、もしくはプリファレンスがIntentの呼び出しを指定している場合(<intent>要素を使用)、またはFragmentの表示を指定している場合(android:fragment属性を使用)のみ、インスタンスでこの属性は必要ありません。 android:title- この属性は、ユーザーに表示される設定の名前です。
android:defaultValue- この属性は、システムが
SharedPreferencesファイルに設定する必要がある初期値を指定します。すべての設定のデフォルト値を指定する必要があります。
その他のサポートされている属性については、Preference(と対応するサブクラス)のドキュメントをご覧ください。
図 2. カテゴリを設定してタイトルを付ける。
1. カテゴリは <PreferenceCategory> 要素で指定します。
2. タイトルは、android:title 属性で指定します。
設定のリストが 10 アイテムを超える場合は、タイトルを追加して設定のグループを定義するか、それらのグループを別の画面に表示することをお勧めします。 詳細については、次のセクションで説明します。
設定グループを作成する
10 以上の設定のリストがある場合、ユーザーが目を通して把握し処理することが難しくなる場合があります。 この問題を解決するには、設定の一部またはすべてをグループに分割し、1 つの長いリストを複数の短いリストに変えます。 関連設定のグループは、次の 2 つの方法のいずれかで表示できます。
これらのグループ化方法の 1 つまたは両方を利用して、アプリの設定を整理できます。使用する方法と設定の分割方法を決定する際は、Android Design のSettings ガイドのガイドラインに従ってください。
タイトルを使用する
設定のグループ間にある見出しに区切り線を入れる場合(図 2 参照)、Preference オブジェクトをグループごとに 1 つの PreferenceCategory 内にセットしてください。
次に例を示します。
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="@string/pref_sms_storage_title"
android:key="pref_key_storage_settings">
<CheckBoxPreference
android:key="pref_key_auto_delete"
android:summary="@string/pref_summary_auto_delete"
android:title="@string/pref_title_auto_delete"
android:defaultValue="false"... />
<Preference
android:key="pref_key_sms_delete_limit"
android:dependency="pref_key_auto_delete"
android:summary="@string/pref_summary_delete_limit"
android:title="@string/pref_title_sms_delete"... />
<Preference
android:key="pref_key_mms_delete_limit"
android:dependency="pref_key_auto_delete"
android:summary="@string/pref_summary_delete_limit"
android:title="@string/pref_title_mms_delete" ... />
</PreferenceCategory>
...
</PreferenceScreen>
サブ画面を使用する
設定のグループをサブ画面に配置する場合(図 3 参照)、Preference オブジェクトのグループを PreferenceScreen 内にセットしてください。
図3. 子画面を設定する。<PreferenceScreen> 要素は、選択されると個別のリストを開き、ネストされた設定を表示するアイテムを作成します。
次に例を示します。
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<!-- opens a subscreen of settings -->
<PreferenceScreen
android:key="button_voicemail_category_key"
android:title="@string/voicemail"
android:persistent="false">
<ListPreference
android:key="button_voicemail_provider_key"
android:title="@string/voicemail_provider" ... />
<!-- opens another nested subscreen -->
<PreferenceScreen
android:key="button_voicemail_setting_key"
android:title="@string/voicemail_settings"
android:persistent="false">
...
</PreferenceScreen>
<RingtonePreference
android:key="button_voicemail_ringtone_key"
android:title="@string/voicemail_ringtone_title"
android:ringtoneType="notification" ... />
...
</PreferenceScreen>
...
</PreferenceScreen>
インテントを使用する
設定画面ではなく、ウェブページを表示するためのウェブブラウザなどの別のアクティビティを開くプリファレンス アイテムが必要になることもあります。
ユーザーがプリファレンス アイテムを選択したときに Intent が呼び出されるようにするには、対応する <Preference> 要素の子として <intent> 要素を追加します。
たとえば、次の方法で、プリファレンス アイテムを使用してウェブページを開くことができます。
<Preference android:title="@string/prefs_web_page" >
<intent android:action="android.intent.action.VIEW"
android:data="http://www.example.com" />
</Preference>
次の属性を使用して、明示的なインテントと黙示的なインテントの両方を作成できます。
android:actionsetAction()メソッドで割り当てるアクション。android:datasetData()メソッドで割り当てるデータ。android:mimeTypesetType()メソッドで割り当てる MIME タイプ。android:targetClasssetComponent()メソッドでのコンポーネント名のクラス部分。android:targetPackagesetComponent()メソッドでのコンポーネント名のパッケージ部分。
プリファレンス アクティビティを作成する
アクティビティに設定を表示するには、PreferenceActivity クラスを継承します。このクラスは、Preference オブジェクトの階層に基づいて設定のリストを表示する従来の Activity クラスを継承したものです。PreferenceActivity は、ユーザーが変更を行ったときに、各 Preference に対応する設定を自動的に保存します。
注: Android 3.0 以降向けにアプリケーションを開発する場合は、代わりに PreferenceFragment を使用する必要があります。
プリファレンス フラグメントの使用についての詳細は、次のセグメントをご覧ください。
onCreate() のコールバック時に、ビューのレイアウトをロードしてはならないことを忘れないよう注意してください。代わりに addPreferencesFromResource() を呼び出し、XML ファイルで宣言済みのプリファレンスをアクティビティに追加する必要があります。
以下は、PreferenceActivity を機能させるために最小限必要なコードです。
public class SettingsActivity extends PreferenceActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
}
ユーザーがプリファレンスを変更するとすぐに、ユーザーの設定のチェックが必要なときに他のアプリケーション コンポーネントが読み取ることができるデフォルトの SharedPreferences ファイルにシステムによって変更が保存されるため、実際一部のアプリではこのコードで十分です。
ただし、多くのアプリでは、プリファレンスに発生する変化をリッスンするために、もう少し多くのコードが必要になります。SharedPreferences ファイルの変更のリッスンについての詳細は、プリファレンスの読み取りについてのセクションをご覧ください。
プリファレンス フラグメントを使用する
Android 3.0(API レベル 11)以降向けに開発を行っている場合は、PreferenceFragment を使用して Preference オブジェクトのリストを表示する必要があります。
PreferenceFragment はどのアクティビティにでも追加できます — PreferenceActivity を使用する必要はありません。
作成するアクティビティの種類にかかわらず、フラグメントを使用すると、アクティビティを単体で使用する場合と比べて、柔軟なアーキテクチャを持つアプリケーションを作成できます。
そのため、可能な限り PreferenceActivity ではなく、PreferenceFragment を使用して設定の表示を管理することをお勧めします。
PreferenceFragment の実装は、onCreate() メソッドを addPreferencesFromResource() を使用してプリファレンス ファイルをロードするように定義するだけと簡単です。
次に例を示します。
public static class SettingsFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preferences);
}
...
}
他の Fragment と同様に、このフラグメントは Activity に追加できます。
次に例を示します。
public class SettingsActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Display the fragment as the main content.
getFragmentManager().beginTransaction()
.replace(android.R.id.content, new SettingsFragment())
.commit();
}
}
注: PreferenceFragment は、独自の Context オブジェクトを持ちません。
Context オブジェクトが必要な場合は、getActivity() を呼び出すことができます。
ただし、getActivity() はフラグメントがアクティビティにアタッチされている場合にのみ呼び出すようにしてください。
フラグメントがまだアタッチされていない場合や、ライフサイクルの終了時にデタッチされた場合は、getActivity() は null を返します。
デフォルト値を設定する
作成するプリファレンスは、多くの場合、アプリケーションにとって重要ないくつかの動作を定義します。そのため、ユーザーが最初にプリケーションを開いたときに、各 Preference のデフォルト値で、関連する SharedPreferences ファイルを初期化する必要があります。
まず、android:defaultValue 属性を使用して、XML ファイルの各 Preference オブジェクトにデフォルト値を指定してください。
指定する値は、対応する Preference オブジェクトで使用できるデータ型であればどのようなデータ型でもかまいません。
次に例を示します。
<!-- default value is a boolean -->
<CheckBoxPreference
android:defaultValue="true"
... />
<!-- default value is a string -->
<ListPreference
android:defaultValue="@string/pref_syncConnectionTypes_default"
... />
次に、アプリケーションのメイン アクティビティ、およびユーザーがアプリケーションを最初に開いたときに表示されるその他のアクティビティの onCreate() メソッドから、setDefaultValues() を呼び出します。
PreferenceManager.setDefaultValues(this, R.xml.advanced_preferences, false);
onCreate() 時に、このメソッドを呼び出すと、アプリケーションがデフォルト設定で適切に初期化されます。アプリケーションには、動作(セルラー ネットワーク上でデータをダウンロードするかどうかなど)を決定するために、デフォルト設定を読み込むことが必要な場合があります。
このメソッドは次の 3 つの引数を取ります。
- アプリケーションの
Context。 - デフォルト値を設定するプリファレンス XML ファイルのリソース ID。
- デフォルト値を複数回設定すべきかどうかを示すブール値。
falseの場合、デフォルト値は過去にこのメソッドが 1 度も呼ばれたことがない場合(または、デフォルト値の共有プリファレンス ファイルのKEY_HAS_SET_DEFAULT_VALUESが false の場合)のみ設定されます。
この 3 番目の引数を false に設定している限り、アクティビティが開始するたびに、ユーザーが保存したプリファレンスをデフォルト値にリセットして上書きすることなく、安全にこのメソッドを呼び出すことができます。
この引数を true に設定した場合は、以前の値がすべてデフォルト値で上書きされます。
プリファレンス ヘッダーを使用する
まれに、最初の画面がサブ画面のリストのみを表示するように設定を設計した方がよい場合もあります(図 4. と図 5. のシステム設定アプリなど)。
このような設計を Android 3.0 以降で開発する場合、ネストした PreferenceScreen 要素でサブ画面を作成するのではなく、「ヘッダー」機能を使用する必要があります。
ヘッダーを使用して設定を作成するには、次の準備が必要です。
- 設定をグループごとに
PreferenceFragmentの別々のインスタンスに分けます。この場合、設定のグループごとに、個別の XML ファイルが必要になります。 - 各設定グループをリストアップし対応する設定のリストを含むのがどのフラグメントかを宣言する XML ヘッダー ファイルを作成します。
PreferenceActivityクラスを継承し、設定をホストします。onBuildHeaders()コールバックを実装して、ヘッダー ファイルを指定します。
この設計を使用する大きなメリットは、大きな画面で実行する場合に、PreferenceActivity によって自動的に図. 4 の 2 ペイン レイアウトで表示されることです。
アプリケーションが 3.0 より前のバージョンの Android をサポートしている場合でも、3.0 より前の端末で従来の多画面階層をサポートしながら、PreferenceFragment を使用して 3.0 以降の端末で 2 ペイン表示を行うことができます(詳細については、旧バージョンでのプリファレンス ヘッダーのサポートについてのセクションをご覧ください)。
図 4. ヘッダー付きの 2 ペイン レイアウト。
1. ヘッダーは、XML ヘッダー ファイルで定義します。
2. 設定の各グループは、XML ヘッダー ファイルの <header> 要素で指定された PreferenceFragment ファイルで定義します。
図 5. ヘッダーが設定されたモバイル端末。アイテムが選択されると、対応する PreferenceFragment がヘッダーを置き換えます。
ヘッダー ファイルを作成する
ヘッダーのリストの設定の各グループは、ルート <preference-headers> 要素内の単独の <header> 要素によって指定されます。
次に例を示します。
<?xml version="1.0" encoding="utf-8"?>
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
<header
android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentOne"
android:title="@string/prefs_category_one"
android:summary="@string/prefs_summ_category_one" />
<header
android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentTwo"
android:title="@string/prefs_category_two"
android:summary="@string/prefs_summ_category_two" >
<!-- key/value pairs can be included as arguments for the fragment. -->
<extra android:name="someKey" android:value="someHeaderValue" />
</header>
</preference-headers>
android:fragment 属性を使用して、各ヘッダーは、ユーザーがヘッダーを選択したときに開く PreferenceFragment のインスタンスを宣言します。
<extras> 要素を使用すると、キーと値のペアを Bundle のフラグメントに渡すことができます。getArguments() を呼び出すことで、フラグメントは引数を取得できます。フラグメントに引数を渡す理由はさまざまですが、各グループの PreferenceFragment の同じサブクラスを再利用し、引数を使用してフラグメントがロードするプリファレンス XML ファイルを指定することは、効果的な引数の使い方の 1 つです。
たとえば、次のフラグメントは、各ヘッダーが "settings" キーを使用して <extra> 引数を定義している場合、複数の設定グループで再利用できます。
public static class SettingsFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String settings = getArguments().getString("settings");
if ("notifications".equals(settings)) {
addPreferencesFromResource(R.xml.settings_wifi);
} else if ("sync".equals(settings)) {
addPreferencesFromResource(R.xml.settings_sync);
}
}
}
ヘッダーを表示する
プリファレンス ヘッダーを表示するには、onBuildHeaders() コールバックメソッドを実装し、loadHeadersFromResource() を呼び出す必要があります。
次に例を示します。
public class SettingsActivity extends PreferenceActivity {
@Override
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.preference_headers, target);
}
}
ユーザーがヘッダーのリストからアイテムを選択した場合、システムが対応する PreferenceFragment を開きます。
注: プリファレンス ヘッダーを使用する場合、アクティビティで必要なタスクはヘッダーのロードのみであるため、PreferenceActivity のサブクラスが onCreate() メソッドを実装する必要はありません。
旧バージョンでプリファレンス ヘッダーをサポートする
アプリケーションが Android 3.0 よりも前のバージョンをサポートしている場合でも、3.0 以降で実行するときに、ヘッダーを使用して 2 ペイン レイアウトを提供できます。
必要なことは、3.0 よりも前のバージョンの Android で使用するために、ヘッダー アイテムのように動作する基本的な <Preference> 要素を使用する追加のプリファレンス XML ファイルを作成することだけです。
新しい PreferenceScreen を開く代わりに、各 <Preference> 要素が、ロードするプリファレンス XML ファイルが指定されている PreferenceActivity に Intent を送ります。
たとえば、以下は Android 3.0 以降で使用されるプリファレンス ヘッダーの XML ファイル(res/xml/preference_headers.xml)です。
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
<header
android:fragment="com.example.prefs.SettingsFragmentOne"
android:title="@string/prefs_category_one"
android:summary="@string/prefs_summ_category_one" />
<header
android:fragment="com.example.prefs.SettingsFragmentTwo"
android:title="@string/prefs_category_two"
android:summary="@string/prefs_summ_category_two" />
</preference-headers>
また、以下は Android 3.0 よりも前のバージョンに同じヘッダーを提供するプリファレンス ファイル(res/xml/preference_headers_legacy.xml)です。
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<Preference
android:title="@string/prefs_category_one"
android:summary="@string/prefs_summ_category_one" >
<intent
android:targetPackage="com.example.prefs"
android:targetClass="com.example.prefs.SettingsActivity"
android:action="com.example.prefs.PREFS_ONE" />
</Preference>
<Preference
android:title="@string/prefs_category_two"
android:summary="@string/prefs_summ_category_two" >
<intent
android:targetPackage="com.example.prefs"
android:targetClass="com.example.prefs.SettingsActivity"
android:action="com.example.prefs.PREFS_TWO" />
</Preference>
</PreferenceScreen>
<preference-headers> のサポートは Android 3.0 で追加されたため、Android 3.0 以降で実行されている場合のみ、システムは PreferenceActivity の onBuildHeaders() を呼び出します。
「レガシー」ヘッダー ファイル(preference_headers_legacy.xml)をロードするには、Android のバージョンを確認し、Android 3.0(HONEYCOMB})よりも前のバージョンの場合、addPreferencesFromResource() を呼び出す必要があります。
次に例を示します。
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
// Load the legacy preferences headers
addPreferencesFromResource(R.xml.preference_headers_legacy);
}
}
// Called only on Honeycomb and later
@Override
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.preference_headers, target);
}
残りの手順は、アクティビティに渡される Intent を処理して、ロードするプリファレンス ファイルを指定するだけです。
それには、インテントのアクションを取得し、プリファレンス XML の <intent> タグで使用した既知のアクション文字列と比較します。
final static String ACTION_PREFS_ONE = "com.example.prefs.PREFS_ONE";
...
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String action = getIntent().getAction();
if (action != null && action.equals(ACTION_PREFS_ONE)) {
addPreferencesFromResource(R.xml.preferences);
}
...
else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
// Load the legacy preferences headers
addPreferencesFromResource(R.xml.preference_headers_legacy);
}
}
addPreferencesFromResource() の連続呼び出しは、すべてのプリファレンスを 1 つのリストにスタックすることに注意してください。そのため、else if ステートメントを使用して条件を適切に記述して、1 度のみ呼び出されるようにしてください。
プリファレンスを読み込む
デフォルトでは、アプリのプリファレンスは、静的メソッド PreferenceManager.getDefaultSharedPreferences() を呼び出すとアプリケーション内のどこからでもアクセス可能なファイルに保存されます。
このメソッドは、PreferenceActivity で使用される Preference オブジェクトに関連するすべてのキーと値のペアを含む SharedPreferences オブジェクトを返します。
たとえば、次の方法で、アプリケーションのその他のアクティビティからプリファレンスの値の 1 つを読み込むことができます。
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); String syncConnPref = sharedPref.getString(SettingsActivity.KEY_PREF_SYNC_CONN, "");
プリファレンスの変化をリッスンする
さまざまな理由で、ユーザーがプリファレンスを変更してすぐに通知を受け取ることが必要になることがあります。
プリファレンスの 1 つに変化が発生したときにコールバックを受け取るには、 SharedPreference.OnSharedPreferenceChangeListener インターフェースを実装し、registerOnSharedPreferenceChangeListener() を呼び出して SharedPreferences オブジェクトにリスナを登録します。
このインターフェースには、コールバック メソッドが onSharedPreferenceChanged() 1 つのみしか含まれておらず、アクティビティの一部として簡単に実装できます。
次に例を示します。
public class SettingsActivity extends PreferenceActivity
implements OnSharedPreferenceChangeListener {
public static final String KEY_PREF_SYNC_CONN = "pref_syncConnectionType";
...
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) {
if (key.equals(KEY_PREF_SYNC_CONN)) {
Preference connectionPref = findPreference(key);
// Set summary to be the user-description for the selected value
connectionPref.setSummary(sharedPreferences.getString(key, ""));
}
}
}
この例では、メソッドが、変更された設定が、既知のプリファレンス キーの設定かどうかチェックしています。メソッドは findPreference() を呼び出して、変更された Preference オブジェクトを取得しています。これにより、メソッドは、ユーザー選択の説明として表示されるアイテムの概要を変更できます。
つまり、その設定が ListPreference またはその他の複数選択可な設定の場合、設定が変更されたときに setSummary() を呼び出して現在のステータス(図 5 のスリープ設定など)を表示する必要があります。
注: Android Design の Settings に説明されているように、ユーザーがプリファレンスを変更するごとに、ListPreference の概要を更新して最新の設定を表示することをお勧めします。
アクティビティでの適切なライフサイクル管理のために、onResume() と onPause() のそれぞれのコールバック時に、SharedPreferences.OnSharedPreferenceChangeListener の登録と登録解除を行うことをお勧めします。
@Override
protected void onResume() {
super.onResume();
getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
}
@Override
protected void onPause() {
super.onPause();
getPreferenceScreen().getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(this);
}
警告: registerOnSharedPreferenceChangeListener() を呼び出す場合、現時点では、プリファレンス マネージャーにはリスナへの強い参照を格納できません。
リスナへの強い参照を格納しない場合は、リスナがガベージ コレクションの影響を受けやすくなります。
リスナが必要な間存在し続けるオブジェクトのインスタンス データ内に、リスナへの参照を保持することをお勧めします。
たとえば、以下のコードでは、呼び出し元は、リスナへの参照を保持していません。 結果として、リスナはガベージ コレクションの影響を受けることになり、その後のいずれかの時点でエラーになります。
prefs.registerOnSharedPreferenceChangeListener(
// Bad! The listener is subject to garbage collection!
new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
// listener implementation
}
});
そのため、リスナが必要な間存在し続けるオブジェクトのインスタンス データ フィールドに、リスナへの参照を格納してください。
SharedPreferences.OnSharedPreferenceChangeListener listener =
new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
// listener implementation
}
};
prefs.registerOnSharedPreferenceChangeListener(listener);
ネットワークの使用を管理する
Android 4.0 以降では、フォアグラウンドとバックグラウンドでのアプリケーションのネットワーク データの使用量を、システムの設定アプリケーションでユーザーが確認できます。 また、ユーザーは、個々のアプリのバックグラウンド データの使用を無効にできます。 アプリのバックグラウンドからのデータへのアクセスをユーザーが無効にすることを防ぐには、データ接続を効率的に使用することと、アプリケーションの設定でアプリのデータの利用方法をユーザーが調整できるようにすることが必要です。
たとえば、データを同期する頻度や、Wi-Fi 上でのみアップロードやダウンロードを実行するようにするかどうか、ローミング時にデータを使用するかどうかなどを、ユーザーが設定できるようにすることができます。 これらをユーザーが管理できる場合、システム設定に設定した限度にデータ使用量が近づいたときに、データへのアプリのアクセスをユーザーが無効にする可能性は減少します。ユーザーはアプリのアクセスを無効にする代わりに、アプリのデータの使用量を厳密に管理できます。
アプリのデータ使用を管理するために PreferenceActivity に必要なプリファレンスを追加したら、マニフェスト ファイルに ACTION_MANAGE_NETWORK_USAGE のインテント フィルタを追加する必要があります。
次に例を示します。
<activity android:name="SettingsActivity" ... >
<intent-filter>
<action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
このインテント フィルタは、これがアプリケーションのデータ使用をコントロールしているアクティビティであるとシステムに示します。
これにより、ユーザーがシステム設定アプリからアプリのデータ使用量を調べるときに、[View application settings] ボタンを使用できるようになります。このボタンを押すと、PreferenceActivity が開始し、アプリのデータ使用量を調整できるようになります。
カスタム プリファレンスを作成する
Android フレームワークには、異なる設定タイプの UI を作成できるさまざまな Preference サブクラスが含まれています。ただし、必要とする設定に、番号ピッカーや日付ピッカーなどの組み込みソリューションがない可能性もあります。
このような場合、Preference クラスまたは他のサブクラスの 1 つを継承して、カスタム プリファレンスを作成する必要があります。
Preference クラスを継承する場合、次のことが必要です。
- ユーザーがその設定を選択したときに表示されるユーザー インターフェースを指定する。
- 適切なタイミングで設定の値を保存する。
Preferenceが表示されるときに、現在の値(またはデフォルト値)で初期化する。- システムによってリクエストされた場合にデフォルト値を提供する。
Preferenceが独自の UI(ダイアログなど)を提供している場合、状態を保存し復元してライフサイクルの変化を処理する(ユーザーが画面を回転させた場合など)。
以下の各セクションでは、上記の各事項を実現する方法を説明します。
ユーザー インターフェースを指定する
Preference クラスを直接継承する場合、onClick() を実装して、ユーザーがアイテムを選択したときに発生するアクションを定義する必要があります。
ただし、大部分のカスタム設定では、手順が簡単な DialogPreference を継承してダイアログを表示する方法が利用されています。
DialogPreference を継承する場合、クラス コンストラクタで setDialogLayoutResourcs() を呼び出してダイアログのレイアウトを指定する必要があります。
たとえば、以下のカスタム DialogPreference のコンストラクタでは、レイアウトを宣言しデフォルトのポジティブとネガティブのダイアログ ボタンのテキストを指定しています。
public class NumberPickerPreference extends DialogPreference {
public NumberPickerPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setDialogLayoutResource(R.layout.numberpicker_dialog);
setPositiveButtonText(android.R.string.ok);
setNegativeButtonText(android.R.string.cancel);
setDialogIcon(null);
}
...
}
設定の値を保存する
設定の値が整数の場合、またはブール値を保存するpersistBoolean() の場合、persistInt() など、Preference クラスの persist*() メソッドのいずれかを呼び出すことで、設定の値をいつでも保存できます。
注: 各 Preference には、1 つのデータ型のデータのみ保存できます。そのため、カスタム Preference で使用されているデータ型に対応する persist*() メソッドを使用する必要があります。
設定をいつ保存したらよいかは、継承する Preference クラスによって異なります。DialogPreference を継承する場合、ポジティブな結果でダイアログが閉じられたとき(ユーザーが [OK] ボタンを選択したとき)のみ、値を保存する必要があります。
DialogPreference が閉じられたときには、システムが onDialogClosed() メソッドを呼び出します。このメソッドには、ユーザーの結果が「Positive」かどうかを指定するブール値の引数が含まれています — この値が true の場合はユーザーがポジティブ ボタンを選択しているということであり、新しい値を保存する必要があります。
次に例を示します。
@Override
protected void onDialogClosed(boolean positiveResult) {
// When the user selects "OK", persist the new value
if (positiveResult) {
persistInt(mNewValue);
}
}
この例では、mNewValue は、設定の現在の値を保持するクラスの 1 つです。
persistInt() を呼び出すと、値が SharedPreferences ファイルに保存されます(この Preference の XML ファイルに指定されたキーを自動的に使用して保存されます)。
現在の値を初期化する
システムは Preference を画面に追加すると、onSetInitialValue() を呼び出し、その設定用に保存されている値がある場合は通知します。
保存されている値がない場合、この呼び出しによりデフォルト値が設定されます。
この onSetInitialValue() メソッドは、ブール値の restorePersistedValue を、その設定用に値が保存済みかどうか示すために渡します。
true の場合、Preference クラスの getPersisted*() メソッド(整数用の getPersistedInt() など)のいずれかを呼び出して保存されている値を取得する必要があります。
通常は保存されている値を取得するのは、UI を更新して以前保存した値を反映させるためです。
restorePersistedValue が false の場合、2 番目の引数で渡されたデフォルト値を使用する必要があります。
@Override
protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
if (restorePersistedValue) {
// Restore existing state
mCurrentValue = this.getPersistedInt(DEFAULT_VALUE);
} else {
// Set default state from the XML attribute
mCurrentValue = (Integer) defaultValue;
persistInt(mCurrentValue);
}
}
各 getPersisted*() メソッドは、値が保存されていない場合またはキーが存在しない場合に使用するデフォルト値を指定する引数を取ります。
上記の例では、getPersistedInt() が保存されている値を返すことができない場合に備えて、ローカル定数がデフォルト値を指定するために使用されています。
警告: defaultValue は、restorePersistedValue が true の場合、常に null になるため、getPersisted*() メソッドでデフォルト値として使用できません。
デフォルト値を提供する
Preference クラスのインスタンスがデフォルト値を指定している場合(android:defaultValue 属性を使用)、システムは、オブジェクトのインスタンスを作成するときに onGetDefaultValue() を呼び出してデフォルト値を取得します。
システムでデフォルト値を SharedPreferences に保存するには、このメソッドを実装する必要があります。
次に例を示します。
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getInteger(index, DEFAULT_VALUE);
}
このメソッドの引数によって、必要なすべての情報(属性の配列と android:defaultValue のインデックス位置)を取得します。
属性からデフォルト値を抽出するためにこのメソッドの実装が必要なのは、デフォルト値が定義されていないときのために属性のローカル デフォルト値を指定する必要があるためです。
プリファレンスの状態を保存し復元する
レイアウトの View と同じく、Preference サブクラスは、アクティビティやフラグメントが再開される場合(ユーザーが画面を回転させた場合など)に状態の保存と復元を担当します。
Preference クラスの状態を適切に保存し復元するには、ライフサイクル コールバック メソッドの onSaveInstanceState() と onRestoreInstanceState() を実装する必要があります。
Preference の状態は、Parcelable インターフェースを実装するオブジェクトによって定義されます。
Android フレームワークでは、このようなオブジェクトである Preference.BaseSavedState クラスが状態オブジェクトを定義するためのベースクラスとして提供されています。
Preference クラスが状態を保存する方法を定義するには、Preference.BaseSavedState クラスを継承する必要があります。
いくつかのメソッドをオーバーライドして CREATOR オブジェクトを定義してください。
大部分のアプリでは、Preference サブクラスが整数以外のデータ型のデータを保存している場合は、次の実装をコピーして、value を処理している行を変更するだけで使用できます。
private static class SavedState extends BaseSavedState {
// Member that holds the setting's value
// Change this data type to match the type saved by your Preference
int value;
public SavedState(Parcelable superState) {
super(superState);
}
public SavedState(Parcel source) {
super(source);
// Get the current preference's value
value = source.readInt(); // Change this to read the appropriate data type
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
// Write the preference's value
dest.writeInt(value); // Change this to write the appropriate data type
}
// Standard creator object using an instance of this class
public static final Parcelable.Creator<SavedState> CREATOR =
new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
Preference.BaseSavedState の上記の実装をアプリに追加(通常、Preference サブクラスのサブクラスとして追加)するとともに、Preference サブクラスの onSaveInstanceState() と onRestoreInstanceState() メソッドを実装する必要があります。
次に例を示します。
@Override
protected Parcelable onSaveInstanceState() {
final Parcelable superState = super.onSaveInstanceState();
// Check whether this Preference is persistent (continually saved)
if (isPersistent()) {
// No need to save instance state since it's persistent,
// use superclass state
return superState;
}
// Create instance of custom BaseSavedState
final SavedState myState = new SavedState(superState);
// Set the state's value with the class member that holds current
// setting value
myState.value = mNewValue;
return myState;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
// Check whether we saved the state in onSaveInstanceState
if (state == null || !state.getClass().equals(SavedState.class)) {
// Didn't save the state, so call superclass
super.onRestoreInstanceState(state);
return;
}
// Cast state to custom BaseSavedState and pass to superclass
SavedState myState = (SavedState) state;
super.onRestoreInstanceState(myState.getSuperState());
// Set this Preference's widget to reflect the restored state
mNumberPicker.setValue(myState.value);
}