Android的Preference

来源:互联网 发布:iphone延时摄影软件 编辑:程序博客网 时间:2024/05/29 12:49

PreferenceActivity

要在 Activity 中显示您的设置,请扩展 PreferenceActivity 类。这是传统 Activity 类的扩展,该类根据 Preference 对象的层次结构显示设置列表。当用户进行更改时,PreferenceActivity 会自动保留与每个 Preference 相关的设置。

注:如果您是开发针对 Android 3.0 及 更高版本系统的应用,则应改为使用 PreferenceFragment。转到下文有关使用首选项片段的部分。

请记住最重要的一点,就是不要在 onCreate() 回调期间加载视图的布局。相反,请调用 addPreferencesFromResource() 以将在 XML 文件中声明的首选项添加到 Activity。例如,一个能够正常工作的 PreferenceActivity 至少需要如下代码:

public class SettingsActivity extends PreferenceActivity {    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        addPreferencesFromResource(R.xml.preferences);    }}

实际上,对于某些应用而言此,代码就已足够,因为用户修改某首选项后,系统会立即将所做的更改保存到默认 SharedPreferences 文件中,如需检查用户的设置,可以使用您的其他应用组件读取该文件。 不过,许多应用需要的代码要稍微多一点,以侦听首选项发生的变化。有关侦听 SharedPreferences 文件变化的信息,请参阅读取首选项部分。

PreferenceFragment

如果您是开发针对 Android 3.0(API 级别 11)及更高版本系统的应用,则应使用 PreferenceFragment 显示 Preference 对象的列表。您可以将 PreferenceFragment 添加到任何 Activity,而不必使用 PreferenceActivity。

与仅使用上述 Activity 相比,无论您在构建何种 Activity,片段都可为应用提供一个更加灵活的体系结构。 因此,我们建议您尽可能使用 PreferenceFragment 控制设置的显示,而不是使用 PreferenceActivity。

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()。但请注意,只应在该片段附加到 Activity 时才调用 getActivity()。如果该片段尚未附加或在其生命周期结束期间已分离,则 getActivity() 将返回空 null。

Preference Headers

在极少数情况下,您可能需要设计设置,使第一个屏幕仅显示子屏幕的列表(例如在系统“设置”应用中,如图 4 和图 5 所示)。 在开发针对 Android 3.0 及更高版本系统的此类设计时,您应该使用 Android 3.0 中的新“标头”功能,而非使用嵌套的 PreferenceScreen 元素构建子屏幕。使用此设计的一大好处是,在大屏幕上运行时,PreferenceActivity 会自动提供双窗格布局.

要使用标头构建设置,您需要:

  1. 将每组设置分成单独的 PreferenceFragment 实例。即,每组设置均需要一个单独的 XML 文件。
  2. 创建 XML 标头文件,其中列出每个设置组并声明哪个片段包含对应的设置列表。
    每个标头均可使用 android:fragment 属性声明在用户选择该标头时应打开的 PreferenceFragment 实例。
<?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>

3.扩展 PreferenceActivity 类以托管设置。
4.实现 onBuildHeaders() 回调以指定标头文件。
要显示首选项标头,您必须实现 onBuildHeaders() 回调方法并调用 loadHeadersFromResource()。例如:

public class SettingsActivity extends PreferenceActivity {    @Override    public void onBuildHeaders(List<Header> target) {        loadHeadersFromResource(R.xml.preference_headers, target);    }}

当用户从标头列表中选择一个项目时,系统会打开相关的 PreferenceFragment。

注:使用首选项标头时,PreferenceActivity 的子类无需实现 onCreate() 方法,因为 Activity 唯一所需执行的任务就是加载标头。

侦听数据变更

出于某些原因,您可能希望在用户更改任一首选项时立即收到通知。 要在任一首选项发生更改时收到回调,请实现 SharedPreference.OnSharedPreferenceChangeListener 接口,并通过调用 registerOnSharedPreferenceChangeListener() 为 SharedPreferences 对象注册侦听器。

该接口只有 onSharedPreferenceChanged() 一种回调方法,而且您可能会发现在 Activity 过程中实现该接口最为简单。例如:

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 对象,以便能够将项目摘要修改为对用户选择的说明。

若要妥善管理 Activity 生命周期,我们建议您在 onResume() 和 onPause() 回调期间分别注册和注销 SharedPreferences.OnSharedPreferenceChangeListener。
首选项管理器不会在您调用 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);

可能会有人认为这是系统设计的猫腻或者bug,其实不然,这正是Android设计人员的高明之处。将一个(隐式的)局部变量添加到监听器容器中,如果该容器只是一个普通的HashMap,这样会导致内存泄露,因为该容器还有局部变量指向的对象,该对象又隐式持有外部Activity的对象,导致Activity无法被销毁。

原因:

private final WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners =            new WeakHashMap<OnSharedPreferenceChangeListener, Object>();//some code goes herepublic void More ...registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {    synchronized(this) {      mListeners.put(listener, mContent);    }}

从上面的代码可以得知,一个OnSharedPreferenceChangeListener对象实际上是放到了一个WeakHashMap的容器中,这个监听器对象很快就会成为垃圾回收的目标,由于放在WeakHashMap中作为key不会阻止垃圾回收,所以当监听器对象被回收之后,这个监听器也会从mListeners中移除。所以就造成了onSharedPreferenceChanged不会被调用。

构建自定义Preference

Android 框架包括各种 Preference 子类,您可以使用它们为各种不同类型的设置构建 UI。不过,您可能会发现自己需要的设置没有内置解决方案,例如,数字选取器或日期选取器。 在这种情况下,您将需要通过扩展 Preference 类或其他子类之一来创建自定义首选项。

扩展 Preference 类时,您需要执行以下几项重要操作:

指定在用户选择设置时显示的用户界面。
适时保存设置的值。
使用显示的当前(默认)值初始化 Preference。
在系统请求时提供默认值。
如果 Preference 提供自己的 UI(例如对话框),请保存并恢复状态以处理生命周期变更(例如,用户旋转屏幕)。正如布局中的 View 一样,在重启 Activity 或片段时(例如,用户旋转屏幕),Preference 子类也负责保存并恢复其状态。要正确保存并恢复 Preference 类的状态,您必须实现生命周期回调方法 onSaveInstanceState() 和 onRestoreInstanceState()。在EditTextPreferences和ListPreferences的源码中,都重写了这两个方法。

Preference 的状态由实现 Parcelable 接口的对象定义。Android 框架为您提供此类对象,作为定义状态对象(Preference.BaseSavedState 类)的起点。BaseSavedState继承了AbsSavedState,而AbsSavedState实现了Parcelable接口

public abstract class AbsSavedState implements Parcelable

要定义 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() 方法。

@Overrideprotected 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;}@Overrideprotected 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);}
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 卧室床选太大了怎么办 画板的笔尖掉了怎么办 宜家水壶盖子有水怎么办 背滤鱼缸除油膜怎么办 书多了没地方放怎么办 学生在教室内丢手机怎么办 新车尾箱坏了怎么办 放书的箱子烂了怎么办 车钥匙锁后备箱里怎么办 布的收纳箱有味怎么办 车漆清漆层掉了怎么办 副驾驶储物箱卡子断了怎么办 玛莎拉蒂车门打不开怎么办 新买的水杯漏水怎么办 泰迪小狗掉毛怎么办 手机jlc调用接口状态异常怎么办 进门和厕所对着怎么办 p过的照片有竖条怎么办 当照片p出竖条纹怎么办 月子里落下脚心怕风怕凉怎么办 鞋胶把手粘住了怎么办 凉鞋魔术贴长了怎么办 新买的狗一直叫怎么办 刚买的幼犬老叫怎么办 狗狗什么都不吃怎么办 新买的吊扇风小怎么办 夜市卖果汁没电怎么办 榻榻米太长2米45怎么办 木质桌子黏黏的怎么办 白色塑料桌子染色了怎么办 3dmax模型变透明了怎么办 刚养的兔子不吃怎么办 熊猫兔不吃下喝怎么办 熊猫兔感冒了一直打喷嚏怎么办 兔子后腿骨断了怎么办 兔子的腿肿了怎么办 仓鼠喝了牛奶该怎么办 宠物兔不吃不喝怎么办 兔子把木屑吃了怎么办? 小车司机碰瓷大车司机怎么办 在淘宝买到假的护肤品怎么办