PreferenceActivity相关

大多数Settings用的是PreferenceActivity

为了说明这个问题,首先从需求说起。即:现有某一Activity专门用于手机属性设置,那么应该如何做呢?
根据我目前所学知识,会想到Activity + Preference 的组合,前者用于界面的构建,后者用于设置数据的存放。虽然想法是正确的,但是会比较繁琐,因为每个设置选项都要建立与其对应的Preference。
所以 现在有更好的选择了,那就是本文的主角:PreferenceActivity
从名字应该可以看出它其实 Activity 与 Perference 的混合物,它的神奇之处在于既可以充当设置界面,又可以很方便地保存设置数据。我们只需要新建一个继承自PreferenceActivity的Activity,然后在主程序中调用就可以了。这个PreferenceActivity中的设置存储是完全自动的,你不需要再用代码去实现设置的存储,PreferenceActivity创建后会自动创建一个配置文件/data/data/you_package_name/shared_prefs/you_package_name_you_xml_name.xml。

如何操作PreferenceActivity

先从需求说起,常见的手机属性设置都有哪些种类:

1、CheckBox 用于【确定/取消】 某项功能(如:是否静音),对应于:CheckBoxPreference   其在Preference 有一个选项与其自动绑定 下同

2、ListView 用于列出所有选择(如:关于设备),对应于:ListPreference

3、TextView 纯粹为了说明状态(如:信号强度),对应于:Preference

4、Switch 用于【开启/关闭】某项功能(如:Motion),对应于SwitchPreferenceScreen

5、EditText 用于在某些特定的情况下写入数据(如:个人信息),对应于EditTextPreference

6、特殊的preference,如:铃音选择,系统会把这个选项自动绑定到铃音数据上,不用设置其他就可以达到切换铃音的效果,对应于RingtonePreference

操作PreferenceActivity步骤:

  1. 1.       PreferenceActivity界面比较特别在 res/xml/setting.xml

<?xml version="1.0" encoding="utf-8"?>

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >

PreferenceScreen:设置页面,可嵌套形成二级设置页面,用Title参数设置标题。

    <PreferenceCategory android:title="SMS 助手" >

        <CheckBoxPreference

            android:defaultValue="false"

PreferenceCategory:某一类相关的设置,可用Title参数设置标题。

            android:key="smsSilence"

            android:summaryOff="关闭"

            android:summaryOn="开启"

checkbox的默认值

            android:title="静音" />

        <PreferenceScreen android:title="更多选项" >

唯一标记此组件

            <CheckBoxPreference

                android:defaultValue="true"

                android:key="cb21"

checkbox关闭时的summary

                android:summaryOff="关闭"

                android:summaryOn="开启"

组件的标题

                android:title="功能1" />       

            <ListPreference

                android:dialogTitle="请选择论坛"

                android:entries="@array/entries_list_preference"

                android:entryValues="@array/entriesvalue_list_preference"

                android:key="list1"

                android:summary="开发论坛"

                android:title="android forum" />

            <EditTextPreference

                android:defaultValue="Hello EditTextPreference"

edittext组件的对话框标题

                android:dialogTitle="输入设置"

                android:key="et1"

                android:summary="点击输入"

                android:title="EditTextPreference Sample" />

        </PreferenceScreen>

    </PreferenceCategory>

    <PreferenceCategory android:title="其他选项" >

        <RingtonePreference

            android:key="rt1"

            android:summary="选择铃声"

            android:title="RingtonePreference Sample" />

    </PreferenceCategory>

</PreferenceScreen>

某些情况下, 你可能想要一个preference项来打开不同的activity而不是设置界面,就像一个web浏览器来查看一个web页面。当用户选择一个preference项时可以调用Intent来启动。方法就是添加一个<intent>节点到<Preference>节点中,示例代码如下:

<Preference android:title="@string/prefs_web_page" >

    <intent android:action="android.intent.action.VIEW"

          android:data="http://www.example.com" />

</Preference>

另外对listpreference的一些说明:

<?xml version="1.0" encoding="utf-8"?>

<resources>

    <string-array name="entries_list_preference">

        <item>www.anddev.org</item>

        <item>www.eoeandroid.com</item>

        <item>developer.android.com</item>

    </string-array>

    <string-array name="entriesvalue_list_preference">

        <item>1</item>

        <item>2</item>

        <item>3</item>

    </string-array>

</resources>

对于listpreference来说,里面的entries中给出的是给用户看的内容,entryValues是代码中需获取preference的值时的返回值。

对defaultValue,其实在用户第一次打开应用程序时看到的值,因此最好是为每一个preference对象指定一个默认值,然后再onCreate()方法中调用一次setDefaultValue()方法:

PreferenceManager.setDefaultValues(this, R.xml.advanced_preferences, false);

需要注意的是,这个boolean型的参数表示是否多次设置默认值,大部分情况下只需设置一次,因此此处是false。

可以看出,PreferenceActivity界面是由嵌套型的组件及preference的键值对组成,但是如何对用户的一系列操作进行响应呢?在之前学过的Activity中,常用布局里的监听,用findViewById()获得目标View,再在其上注册监听器即可,但是PreferenceActivity并没有提供findViewById()方法,也就无法监听。注意第一段代码中对key的解释:唯一标记此组件。利用组件的key值然后注册change监听器:

得到SharedPreferences句柄

SharedPreferences sp = PreferenceManager

                                     .getDefaultSharedPreferences(this);

sp.registerOnSharedPreferenceChangeListener(new OnSharedPreferenceChangeListener() {

                            // sharedPreferences:句柄

注册改变监听器

                            // key: 改变键值

                            public void onSharedPreferenceChanged(

                                               SharedPreferences sharedPreferences, String key) {

                                     // TODO Auto-generated method stub

 

                                     if (key.equals("autoBack")) {

                                               Boolean autoBack = sharedPreferences.getBoolean("autoBack",

                                                                 false);

                                               if (autoBack) {

对应key值标记组件,并且得到value值

                                                        Log.d("TAG", "autoBack: true!");

                                               } else {

                                                        Log.d("TAG", "autoBack: false!");

                                               }

                                     }

                                     else if (key.equals("smsSilence")) {

                                               //add action

                                     }

                            }

 

                   });

手机设置是对手机全局的改变,通常情况下手机其他应用程序需要改变该数据,其他应用程序如何改变PreferenceActivity的值呢?

首先得到SharedPreferences实例

spc=this.getSharedPreferences("com.android.PreferenceActivity.Usage_setting.xml", MODE_WORLD_READABLE ); 

从spc中通过key获取对应的值

Boolean autoBack = spc.getBoolean("autoBack", false);

赋值:

public void putValue(String key, Boolean value){

spe = spc.edit();

spe.putBoolean(key, value);

spe.commit();

}

使用Preference Fragments

如果在android3.0或更高版本上开发,应该使用PreferenceFragment来显示Preference对象列表。而不应该在使用PreferenceActivity了。因为Fragments提供更为灵活的应用程序结构。

public static class SettingsFragment extends PreferenceFragment {

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        addPreferencesFromResource(R.xml.preferences);

    }

    ...

}

然后把这个fragment添加到Activity中:

public class SettingsActivity extends Activity {

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        getFragmentManager().beginTransaction()

                .replace(android.R.id.content, new SettingsFragment())

                .commit();

    }

}

注意:一个PreferenceFragment没有它自己的Context对象。如果你需要一个Content对象,你能调用getActivity()方法。然而,当fragment没有附加到activity中或者activity声明周期结束时分离后,你使用getActivity()返回的将是null。

我们的代码中使用Preference Headers

在少数情况下,如用首次屏幕显示的时候,可能想要让用户先设置一些配置属性。在android3.0或更高版本系统下,可以使用新的“headers”功能来代替以前的subscreens的嵌套。使用headers步骤如下:

1. 每个单独的设置作为独立PreferenceFragment的实例。即,每组设置需要一个单独的XML文件。

2. 创建一个XML header文件,其中列出了每个设置组和声明这fragment包含相应的设置列表。

3. 继承PreferenceActivity类来托管设置。

4. 实现onBuildHeaders()回调方法用来指定头文件。

有意思的是,在大屏幕上使用Preference Headers这个设计运行时会自动给出双栏布局,如下图。

下面用一段代码来说明如何操作这个好用的Preference Headers

 

 

 

<?xml version="1.0" encoding="utf-8"?>

<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">

    <header

每一个header声明一个PreferenceFragment实例,当用户选择这个header时就会打开这个PreferenceFragment

        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" >

        <extra android:name="someKey" android:value="someHeaderValue" />

这个键值对可以当成一个fragment的参数

    </header>

</preference-headers>

 

 

 

 

对于<extra>的说明:

<extras>节点允许通过键值对的形式传参,一般是使用Bundle。Fragment通过调用getArguments()来得到参数。关于参数的用途比较常见的就是为每一个组重用相同的PreferenceFragment子类并且使用参数制定你将要载入哪一个preferences XML文件。例如,下面是一个fragment,它被多个设置组重用,下面代码清单5-11中在XML中使用了<extra>节点,key为“settings”:

 

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);

        }

    }

}

 

为了实现headers,必须实现onBuildHeaders()回调方法并调用loadHeadersFromResource()方法,如下:

public class SettingsActivity extends PreferenceActivity {

    @Override

    public void onBuildHeaders(List<Header> target) {

        loadHeadersFromResource(R.xml.preference_headers, target);

    }

}

posted @ 2014-10-07 17:32  Simba.Chen  阅读(631)  评论(0编辑  收藏  举报