使用PreferenceFragment创建参数设置列表

本文详细介绍如何利用PreferenceFragment创建应用程序的参数设置列表,包括创建XML配置文件、编写Fragment类及添加事件响应等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天看到一篇很好的文章,详细的介绍了PreferenceFragment创建参数设置列表

《》我们在创建一个应用程序的时候,往往需要创建一个参数设置列表,我们需要将这写参数以Preference的形式保存进SharedPreferencse文件中 ,

注意保存进入SharedPreferences文件中的各条记录,都是一条Preference;令人高兴的是Android为我们专门提供了一个PreferenceFragment类,

这个类是专门用来创建一个参数设置列表的Fragment的,(注意PreferenceActivity已经过时,不再推荐使用)

《》如何使用PreferenceFragment类来创建一个参数设置列表呢?方法如下:

①创建一个XML文件,在这个文件添加多条Preference,这个文件将来会加载到创建的PreferenceFragment类中 , 如:

复制代码
<!--res/xml/preferences.xml文件-->
<?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <CheckBoxPreference android:key="autoSave" android:title="自动保存进度" android:summaryOn="自动保存:开启" android:summaryOff="自动保存:关闭" android:defaultValue="true" /> <ListPreference android:key="gender" android:title="性别" android:summary="选择您的性别" android:dialogTitle="ListPreference" android:entries="@array/gender_name_list" android:entryValues="@array/gender_value_list"/> </PreferenceScreen>
复制代码

上方代码中,PreferenceScreen为根标签,ListPreference为子标签。ListPreference的常见属性如下:

  • android:key 唯一标识符,和android:id相类似,PreferenceManager可以以其为参数通过findPreference获取指定的preference 。

注意,这个android:key的值也是Preference文件里面的XML“键”名

  • android:title 大标题
  • android:summary 标题下面的小字(这个要作为选项卡才有)
  • android:entries 弹出的对话框中,列表显示的文本内容,注意哦,这里指定的是一个数组。
  • android:entryValues 与android:entries相对应的值
  • android:defaultValue 当对应值不存在时的默认值
  • android:dialogTitle 弹出的对话框中的标题信息

关于android:entriesandroid:entryValues的区别,要强调一下:

  • android:entries:The human-readable array to present as a list. 是展现给用户的列表的值。
  • android:entryValues :he array to find the value to save for a preference when an entry from entries is selected.

       展现的用户的选择列表的每个元素选择后,需要存储到手机中,这里的entryValues就是列表中各个元素被选择后存储到手机中的值

     (通过sharedPreferences保存在/data/data/<packagename>/shared_prefs/目录下)。简单的说就是此处是数据库中的值。

      上面的android:entries是展现给用户的列表的值。

  • <ListPreference>标签中,我们使用了定义好的数组xml文件

        android:entries="@array/gender_name_list"

        android:entryValues="@array/gender_value_list"

就是说,我们使用了array数组中的资源来创建<ListPreference>对应的参数选项列表;这个数组资源的定义方式如下:

复制代码
<resources>
<string-array name="gender_name_list">
<item></item>
<item></item>
</ string-array >

<string-array name="gender_value_list">
<item>male</item>
<item>famle</item>
</ string-array >

</ resources >
复制代码

 

②创建一个继承PreferenceFragment类的类,这个是用来加载上面创建的preferences.xml文件的,之后我们就将这个创建一个这个子类的实例对象,并将这个对象加载到Activity中,代码如下:

复制代码
public class SettingsActivityActivity extends Activity {
        //内部类,继承自PreferenceFragment的子类
        public static class SettingsFragment extends PreferenceFragment{
            @Override
            public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
            //加载创建的preference.xml 文件,这个文件的位置在res/xml文件夹下
                addPreferencesFromResource(R.xml.preferences);
            }
        } //SettingFragment类定义完毕
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
        
            //activity_settings_activity.xml是Activity的布局文件,其中只有一个 //<FrameLayout/>用来装载Fragment对象
            setContentView(R.layout.activity_settings_activity);
        
            //加载创建的new SettingsFragment() 对象
            getFragmentManager().beginTransaction()
            .replace(android.R.id.content, new SettingsFragment())
            .commit();
        }  //onCreate方法结束
}  // SettingsActivityActivity类结束
复制代码

《》为参数设置列表添加事件响应——有两种类型的事件响应:

①比如,我们不仅仅想要通过单击上面的参数列表中的“男”“女”,将数据存入SharedPreference文件中,还想要实时的响应这些改变,

比如,一旦我们选择了“男”,那么我就想将android:summary="选择您的性别"  设定的概述文字变成“male”,

也就是说,我们需要实时的响应Preference记录的改变,

那么我们就要通过 使用下面的方法来添加事件响应:

原理:SharedPreferences类中有两个方法,是专门用来监听位于SharedPreferences文件中的各条Preference记录是否发生了改变的:

1、为SharedPreferences注册监听器

void registerOnSharedPreferenceChangeListener

(SharedPreferences.OnSharedPreferenceChangeListener listener)

2、为SharedPreferences撤销监听器

void unregisterOnSharedPreferenceChangeListener

(SharedPreferences.OnSharedPreferenceChangeListener listener)

所以,我们要做的事,非常的简单那就是首先创建一个SharedPreferences.OnSharedPreferenceChangeListener监听器对象,

重写里面的onSharedPreferenceChanged()方法;

之后获得SharedPreferences对象,最后调用上面的两个方法,注册和撤销上面创建的监听器对象,下面举个例子:

使用的依然是preferences.xml文件,和上面的例子一样,只是为创建的SharedPreferences对象添加监听器罢了:

复制代码
public class SettingsActivityActivity extends Activity {
    //内部类,继承自PreferenceFragment的子类,同时实现//OnSharedPreferenceChangeListener接口
    public static class SettingsFragment extends PreferenceFragment 
                                         implements OnSharedPreferenceChangeListener{
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            //加载创建的preference.xml 文件,这个文件的位置在res/xml文件夹下
            addPreferencesFromResource(R.xml.preferences);
           //为创建的SharedPreferences对象更改名字           
getPreferenceManager().setSharedPreferencesName("mysetting");
this.getPreferenceManager() .getSharedPreferences() .registerOnSharedPreferenceChangeListener(this); } @Override public void onSharedPreferenceChanged( SharedPreferences sharedPreferences, String key) { if (key.equals("gender")) { Preference connectionPref = findPreference(key); //一旦“gender“对应的Preference的value改变,就将该列表中的“性别“一栏中的概述“选择您的性别”更改为新选择的value值 connectionPref.setSummary(sharedPreferences.getString(key, "")); } }// onSharedPreferenceChanged()方法结束 }// SettingsFragment内部类定义完毕 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //activity_settings_activity.xml是Activity的布局文件,其中只有一个<FrameLayout/>用来装载Fragment对象 setContentView(R.layout.activity_settings_activity); //加载创建的new SettingsFragment() 对象 getFragmentManager().beginTransaction() .replace(android.R.id.content, new SettingsFragment()) .commit(); } }// SettingsActivityActivity类定义结束
复制代码

 

然而在实际中,我们最好将Fragment或者Activity的生命周期考虑在内,也就是说,我们不要随意的为SharedPreferences添加事件响应,

因为SharedPreferences添加的事件响应器以及SharedPreferences,本身和所在的Fragment或者Activity是分离的, 这样的话,

如果所在的Fragment或者Activity已经处于停止等状态时,就不应该再有事件响应了,也就是说,我们这时就应该使用

unregisterOnSharedPreferenceChangeListener方法,撤销这个监听器

,从而更好地方法是下面的代码:

复制代码
public class SettingsActivityActivity extends Activity {
    //内部类,继承自PreferenceFragment的子类
    public static class SettingsFragment extends PreferenceFragment 
                 implements OnSharedPreferenceChangeListener{
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            //加载创建的preference.xml 文件,这个文件的位置在res/xml文件夹下
            addPreferencesFromResource(R.xml.preferences);
            getPreferenceManager().setSharedPreferencesName("mysetting");
                /*this.getPreferenceManager()
                  .getSharedPreferences()
                  .registerOnSharedPreferenceChangeListener(this);*/
        }
        @Override
        public void onResume() {
            super.onResume();
            getPreferenceScreen().getSharedPreferences()
                    .registerOnSharedPreferenceChangeListener(this);
        }

        @Override
        public  void onPause() {
            super.onPause();
            getPreferenceScreen().getSharedPreferences()
                    .unregisterOnSharedPreferenceChangeListener(this);
        }
        
        @Override
        public void onSharedPreferenceChanged(
                SharedPreferences sharedPreferences, String key) {
            if (key.equals("gender")) {
                Preference connectionPref = findPreference(key);
           // Set summary to be the user-description for the selected value
          connectionPref.setSummary(sharedPreferences.getString(key, ""));
                }
            }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        //activity_settings_activity.xml是Activity的布局文件,其中只有一个 <FrameLayout/>用来装载Fragment对象
        setContentView(R.layout.activity_settings_activity);
        
        //加载创建的new SettingsFragment() 对象
        getFragmentManager().beginTransaction()
        .replace(android.R.id.content, new SettingsFragment())
        .commit();
        
    }
}
复制代码

 

在介绍第二种事件响应之前,我们首先做一下以下几点说明:

..1..       我们知道上面是使用preferences.xml文件作为生成SharedPreferences文件的,那么保存在data/data/包名/shared_prefs文件夹下的

那个用于保存Key—Value键值对的SharedPreferences文件的文件名是什么呢?有人会说应该还是”preferences.xml”,

这实际上是不对的,我们可以通过explorerFile来查看这个文件,可以发现这个文件名为:“包名_preferences.xml”,

这个文件名是唯一能够标识这个SharedPreferences的名字,我们通过getSharedPreferences(string name , int mode)

来返回一个SharedPreferences对象的时候,name 参数就应该是“包名_preferences.xml”,但是这个名字太长了,我们可以通过使用

getPreferenceManager().setSharedPreferencesName("mysetting");

来修改这个文件的名字,就像上面的代码所做的一样。

..2..      我们使用PreferenceFragment只是能够方便的通过系统直接将选定的参数保存进指定的SharedPreferences文件中,只是将数据保存起来了,

但是如果说,我们在上一次程序运行的时候,通过改变的某个参数,将某些组件或者其他的属性更改了(比如,像上面,我们将列表项的summary标题概述给更改了),

那么在关闭程序后,下一次再打开这个程序时,那些更改的属性是不能够自动加载上一次的改变的(也就是说上例中“请选择性别”不会变成“male”),

这也是非常容易理解的,因为程序不可能帮助我们做太多的工作;所以,如果我们想要还原上次的属性,那么我们在程序开始后的某个阶段

(最好在某个合适的生命周期回调方法中)应该读取SharedPreferences,根据这些参数,将一些更改重新加载;

..3..       另外需要注意的一点是,有时有些参数不应该在SharedPreferences中一直保存,比如:我们只想在程序开始的时候(设为①),

读取上一次SharedPreferences保存的Value1,但是,本次程序(①)运行的过程中,我们会为这个参数重新赋一个Value2保存进SharedPreferences,

也就说,上次的Value1,今后就没有用了,那么我们就应该在用完Value1之后,调用相关的方法将Value1从SharedPreferences中删除,

否则,在SharedPreferences文件中就会保存大量的垃圾数据

②SharedPreferences的第二种事件监听类型:

监听事件onPreferenceTreeClick()方法:

publicboolean onPreferenceTreeClick

(PreferenceScreen preferenceScreen Preference preference) 

当任何一个preference控件被点击,都将触发该方法。但是可以通过preference.getKey()这个方法找到具体是哪个preference被点击了,

因为每个preference的key都是唯一的。注意,这个preference.getKey(String key) 返回的是对应的preference记录中的value值 ;

此外,那就是onPreferenceTreeClick(参数) 注册的监听器的事件响应和第一种registerOnSharedPreferenceChangeListener (参数)是不同的,区别在于:registerOnSharedPreferenceChangeListener 的触发事件是:当SharedPreferences中的任意一条preference记录的value值发生改变的时候触发该监听器;而onPreferenceTreeClick的触发事件是:只要单击列表项中任意一项就会触发这个方法,至于列表项所关联的preference的value值变与不变,它是不管的

【实例】

现将preferences.xml这个设置选项的布局文件,定义如下:

复制代码
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >

    <!-- 设置的类别 -->
    <PreferenceCategory
        android:key="mylocation"
        android:summary="我的位置"
        android:title="我的位置源" >
        <CheckBoxPreference
            android:key="wireless_network"
            android:summary="使用无线网络查看应用程序(例如Google地图)中的位置"
            android:title="使用无线网络" />
        <CheckBoxPreference
            android:key="gps_satellite_setting"
            android:summary="定位时,精确到街道级别(取消选择可节约电量)"
            android:title="启用GPS卫星设置" />
    </PreferenceCategory>
    
    <PreferenceCategory
        android:key="mymessage"
        android:summary="个人信息设置"
        android:title="个人信息设置" >
        <CheckBoxPreference
            android:key="yesno_save_individual_info"
            android:title="是否保存个人信息" />
        <EditTextPreference
            android:key="individual_name"
            android:summary="请输入真实姓名"
            android:title="姓名 " />
        <ListPreference
            android:entries="@array/cities"
            android:entryValues="@array/cities"
            android:key="mycity"
            android:summary="所属城市"
            android:title="所属城市" />
    </PreferenceCategory>

</PreferenceScreen>
复制代码

运行效果如下:

从上面的实例可以看出这样的一个问题:只有我们将

里面的复选框选中的时候,“姓名”一栏才应该成为活动状态,否则这一栏应该是非活动状态。

那么我们就可以通过使用onPreferenceTreeClick方法,为SharedPreferences添加监听事件,使得上面的两栏的状态一致:

复制代码
public class PrefFragment extends PreferenceFragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //从xml文件加载选项 
        addPreferencesFromResource(R.xml.preferences);
    }
    @Override
    public boolean onPreferenceTreeClick
(PreferenceScreen preferenceScreen,Preference preference) {
        //如果“保存个人信息”这个按钮被选中,将进行括号里面的操作
    if("yesno_save_individual_info".equals(preference.getKey())) {            
       CheckBoxPreference checkBoxPreference = (CheckBoxPreference)findPreference("yesno_save_individual_info");
       EditTextPreference editTextPreference = (EditTextPreference)findPreference("individual_name");
       //让editTextPreference和checkBoxPreference的状态保持一致          
editTextPreference.setEnabled(checkBoxPreference.isChecked());
} return super.onPreferenceTreeClick(preferenceScreen, preference); } }
复制代码

《》最后我们要说的就是:使用PreferenceFragment,我们还可以通过编写那个preferences.xml文件,

使得显示的参数列表分组(使用<PreferenceCategory>);还可以使得某些列表项能够显示出子屏;方法就是使用多级<PreferenceCategory>标签

例如:

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
    android:title="Settings" >
    <PreferenceScreen
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:summary="settings about emotions"
        android:title="Emotions" >
        <CheckBoxPreference
            android:defaultValue="true"
            android:summaryOff="No,I am sorry."
            android:summaryOn="Yes,I love you!"
            android:title="Love me?" >
        </CheckBoxPreference>
        <CheckBoxPreference
            android:defaultValue="false"
            android:summaryOff="No,you are a good person."
            android:summaryOn="Yes,I hate you!"
            android:title="Hate me?" >
        </CheckBoxPreference>
    </PreferenceScreen>
    
    <PreferenceScreen
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:summary="settings about relations"
        android:title="Relations" >
        <CheckBoxPreference
            android:defaultValue="true"
            android:summaryOff="No,I am sorry."
            android:summaryOn="Yes,we are family!"
            android:title="Family?" >
        </CheckBoxPreference>
        <CheckBoxPreference
            android:defaultValue="false"
            android:summaryOff="No,I am sorry."
            android:summaryOn="Yes,we are friends!"
            android:title="Friends?" >
        </CheckBoxPreference>
    </PreferenceScreen>
</PreferenceScreen>
复制代码

效果如下:

这就是关于PreferenceFragment的几乎所有的内容了,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值