转载:Android的设置界面及Preference使用
原帖地址:http://blog.csdn.net/ichliebephone/article/details/5916320
一.基础知识
我们在使用Android手机时,可能会经常用到其中的设置界面,如下所示:
图1Android系统中的设置界面
而且对于我们自己开发的一个完整的程序来说,我们也会需要给用户提供一个设置界面使用户可以对程序的一些参数进行设置。因此,我们就来学习下如何实现符合我们需要的一个设置界面,及其背后的数据持久化功能。
二.实例开发
2.1SharedPreferences
在具体介绍Android的设置界面的实现之前,我们先来介绍一下预备知识,就是Android数据持久化方法中最简单的一种,即使用Preferences的键值对存储方式。这种方式主要用来存储比较简单的一些数据,而且是标准的Boolean、Int、Float、Long、String等类型。
android.content.SharedPreferences是一个接口,用来获取和修改持久化存储的数据。有三种获取系统中保存的持久化数据的方式:
1.publicSharedPreferencesgetPreferences(intmode)
通过Activity对象获取,获取的是本Activity私有的Preference,保存在系统中的xml形式的文件的名称为这个Activity的名字,因此一个Activity只能有一个,属于这个Activity。
2.publicSharedPreferencesgetSharedPreferences(Stringname,intmode)
因为Activity继承了ContextWrapper,因此也是通过Activity对象获取,但是属于整个应用程序,可以有多个,以第一参数的name为文件名保存在系统中。
3.publicstaticSharedPreferencesgetDefaultSharedPreferences(Contextcontext)
PreferenceManager的静态函数,保存PreferenceActivity中的设置,属于整个应用程序,但是只有一个,Android会根据包名和PreferenceActivity的布局文件来起一个名字保存。
通过以上方式取得SharedPreferences后就可以对数据进行读取或者保存了。
保存方式如下:
[java] view plain copy print ?
- StringSTORE_NAME="Settings";
- SharedPreferencessettings=getSharedPreferences(STORE_NAME,MODE_PRIVATE);
- SharedPreferences.Editoreditor=settings.edit();
- editor.putInt("sourceType",0);
- editor.commit();
获得SharedPreferences,如果需要进行保存等修改操作,首先得通过其edit()方法获得SharedPreferences.Editor,然后就可以通过putInt、putString等方法以键值对(key-value)的方式保存数据,或者remove移除某个键(key),及调用clear方法删除所有内容。最后需要调用commit方法是使修改生效。
读取方式如下:
[java] view plain copy print ?
- SharedPreferencessettings=getSharedPreferences(STORE_NAME,MODE_PRIVATE);
- intsource=settings.getInt("sorceType",1);
读取就更加简单了,只要获得SharedPreferences后,就可以通过getInt、getString等方法获取对应键(key)保存着的数据,如果没有找到key,则返回第二个参数作为默认值。
2.2PreferenceActivity
上面介绍SharedPreferences键值对保存的基础知识,接着我们就可以来实现Android系统的设置界面。Android系统中和设置界面相关的包为android.preference,其中有一个继承了ListActivity的PreferenceActivity。
下面我们就先实现一个如下图2的最简单的PreferenceActivity设置界面,只有一个CheckBox选择选项,选中时显示“Yes,Iloveyou!”,取消选择时显示“No,Iamsorry.”。然后再介绍其具体的实现。
图2PreferenceActivity界面
首先新建一个工程AndroidPreferenceDemo。
把extendsActivity改为extendsPreferenceActivity。
在res目录下新建一个xml文件夹,接着在这个文件夹下新建一个取名为preferences.xml的File文件,内容如下:
[xhtml] view plain copy print ?
- <?xmlversion="1.0"encoding="UTF-8"?>
- <PreferenceScreen
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:title="Settings">
- <CheckBoxPreference
- android:title="Loveme?"
- android:summaryOn="Yes,Iloveyou!"
- android:summaryOff="No,Iamsorry."
- android:defaultValue="true">
- </CheckBoxPreference>
- </PreferenceScreen>
然后把java文件中的setContentView(R.layout.main);改为
addPreferencesFromResource(R.xml.preferences);
完成了,最后可以运行试下效果。
Java文件的实现很简单,继承PreferenceActivity后,调用其publicvoidaddPreferencesFromResource(intpreferencesResId)
方法从一个xml文件中获取preference然后显示为标准的设置界面。
因此我们只要在xml文件中布局好要显示的设置界面内容就可以了。
下面我们看下布局文件xml的内容。
对应的xml中可以使用的标签(Tag)可以分为两类,一类是管理布局的显示,如PreferenceScreen;另一类是具体的设置内容,如CheckBoxPreference。
PreferenceScreen可以显示一个完整的页面,可以嵌套,包含在PreferenceScreen标签里的内容都将以一个完整的页面显示。
我们学习一个PreferenceScreen的界面,如下图3所示。
图3PreferenceScreen相关的布局
当点击左图的选项时,分别会以新的页面显示,如中间和右图所示。
上面页面对应的xml布局文件如下所示:
[xhtml] view plain copy print ?
- <?xmlversion="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:title="Emotions"
- android:summary="settingsaboutemotions">
- <CheckBoxPreference
- android:title="Loveme?"
- android:summaryOn="Yes,Iloveyou!"
- android:summaryOff="No,Iamsorry."
- android:defaultValue="true">
- </CheckBoxPreference>
- <CheckBoxPreference
- android:title="Hateme?"
- android:summaryOn="Yes,Ihateyou!"
- android:summaryOff="No,youareagoodperson."
- android:defaultValue="false">
- </CheckBoxPreference>
- </PreferenceScreen>
- <PreferenceScreen
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:title="Relations"
- android:summary="settingsaboutrelations">
- <CheckBoxPreference
- android:title="Family?"
- android:summaryOn="Yes,wearefamily!"
- android:summaryOff="No,Iamsorry."
- android:defaultValue="true">
- </CheckBoxPreference>
- <CheckBoxPreference
- android:title="Friends?"
- android:summaryOn="Yes,wearefriends!"
- android:summaryOff="No,Iamsorry."
- android:defaultValue="false">
- </CheckBoxPreference>
- </PreferenceScreen>
- </PreferenceScreen>
和管理布局显示相关的除了PreferenceScreen外,还有一个常用的为PreferenceCategory,我们把上面xml文件中间那两个PreferenceScreen改为PreferenceCategory就可以看到PreferenceCategory的显示效果了,如下图4所示。
图4PreferenceCategory相关的布局
可以看到PreferenceCategory是把包含的内容归为同一类,但只是显示在一个页面中。
管理布局相关的两个标签可以使设置内容显示的更有条理,但是更主要的还是具体设置相关的标签,除了我们已经在使用的用于二选一的CheckBoxPreference外,Android系统提供的还有以对话框显示的DialogPreference,可以输入文本的EditTextPreference,以列表方式显示供选择的ListPreference和设置铃声用的RingtonePreference。
下面我们选择比较常用的ListPreference来介绍下具体使用。
首先在res/values/文件夹下新建一个取名为array.xml的文件,内容为:
[xhtml] view plain copy print ?
- <?xmlversion="1.0"encoding="utf-8"?>
- <resources>
- <!--系统设置界面需要要到的数组-->
- <string-arrayname="auto_update_frequency_entry">
- <item>10分钟</item>
- <item>30分钟</item>
- <item>1小时</item>
- <item>12小时</item>
- <item>24小时</item>
- </string-array>
- <string-arrayname="auto_update_frequency_value">
- <item>10</item>
- <item>30</item>
- <item>60</item>
- <item>720</item>
- <item>1440</item>
- </string-array>
- </resources>
然后在res/values/strings.xml文件中添加
[xhtml] view plain copy print ?
- <!--统设置界面需要要到的字符串-->
- <stringname="system_settings">系统设置</string>
- <stringname="auto_update_setting">自动更新设置</string>
- <stringname="auto_update_switch_title">自动更新</string>
- <stringname="auto_update_switch_key">auto_update_switch</string>
- <stringname="auto_update_switch_summary_on">开启自动更新</string>
- <stringname="auto_update_switch_summary_off">关闭自动更新</string>
- <stringname="auto_update_frequency_title">更新频率</string>
- <stringname="auto_update_frequency_key">auto_update_frequency</string>
- <stringname="auto_update_frequency_default_value">10</string>
- <stringname="auto_update_frequency_summary">设置自动更新的时间周期</string>
- <stringname="cancel">取消</string>
需要的数据现在准备好了,下面我们来完成对应的xml文件。xml文件中各个标签的属性比较多,虽然Android有代码自动补全功能,但是还是使用Android提供的Structure界面来填写比较方便,下面我们就以这个方式来完成。
在res/xml文件夹下新建一个AndroidXMLFile文件,取名为preferencesii.xml,类型选择Preference,RootElement选择PreferenceScreen。 在Structure方式显示时,就会列出选中标签的所有属性,然后就可以根据需要填写属性,如下图5所示:
图5填写xml中Preference的属性
从上图我们可以看到一个Preference拥有的属性。其中Key为这个Preference的ID,设置了才可以在代码中引用,Title是显示的标题,Summary是显示在标题下的文字介绍,一般在Dependency中填写一个CheckBoxPreference的Key,这样就会在填写的那个CheckBoxPreference勾选时当前这个Preference才可用,DefaultValue为初始值,等等。
点击“Add”按钮,就会添加新的标签,我们依次添加一个CheckBoxPreference和ListPreference。属于CheckBoxPreference的特有属性主要为SummaryOn和SummaryOff,比较好理解。下面具体来看下ListPreference属性的填写:
图6ListPreference的属性
我们可以看到,ListPreference除了继承自Preference的属性外,还有自己ListPreference的属性和继承自DialogPreference的属性。其中属于ListPreference的属性有两个:Entries填的为一个字符串数组,是列表显示出来的值,而EntryValues是长度对应的字符串数组,是和Entries对应的具体的值。DialogPreference只要填一个Dialogtitle标题和一个取消按钮显示的字即可。在Preference属性的Dependency中我们填写上面一个CheckBoxPreference的Key,这样就会只有在CheckBoxPreference勾选时这个ListPreference才有效。
图7完整的xml显示
最后把java文件中的addPreferencesFromResource(R.xml.preferences);改为addPreferencesFromResource(R.xml.preferencesii);
保存运行,看下效果。
图8ListPreference显示
2.3OnPreferenceChangeListener
以上我们分别介绍了Preference对数据的保存及PreferenceActivity设置界面。当PreferenceActivity中的内容改变时,Android系统会自动进行保存和持久化维护,我们只需要在要用的设置界面中数据的地方进行读取就可以了。同时Android还提供了OnPreferenceClickListener和OnPreferenceChangeListener两个与Preference相关的监听接口,当PreferenceActivity中的某一个Preference进行了点击或者改变的操作时,都会回调接口中的函数,这样可以第一个时间向其他Activity等通知系统设置进行了改变。
下面我们以一个具体的Demo说明PreferenceActivity和其监听接口的使用。
新建一个工程AndroidPreferenceDemoII,并按上面的步骤添加xml文件夹和其内容Preferenceii.xml,还有values文件夹中的array.xml和strings.xml。
新建一个名为Settings的class,内容为:
[java] view plain copy print ?
- //继承PreferenceActivity,并实现OnPreferenceChangeListener和OnPreferenceClickListener监听接口
- publicclassSettingsextendsPreferenceActivityimplementsOnPreferenceChangeListener,
- OnPreferenceClickListener{
- //定义相关变量
- StringupdateSwitchKey;
- StringupdateFrequencyKey;
- CheckBoxPreferenceupdateSwitchCheckPref;
- ListPreferenceupdateFrequencyListPref;
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- //从xml文件中添加Preference项
- addPreferencesFromResource(R.xml.preferencesii);
- //获取各个Preference
- updateSwitchKey=getResources().getString(R.string.auto_update_switch_key);
- updateFrequencyKey=getResources().getString(R.string.auto_update_frequency_key);
- updateSwitchCheckPref=(CheckBoxPreference)findPreference(updateSwitchKey);
- updateFrequencyListPref=(ListPreference)findPreference(updateFrequencyKey);
- //为各个Preference注册监听接口
- updateSwitchCheckPref.setOnPreferenceChangeListener(this);
- updateSwitchCheckPref.setOnPreferenceClickListener(this);
- updateFrequencyListPref.setOnPreferenceChangeListener(this);
- updateFrequencyListPref.setOnPreferenceClickListener(this);
- }
- @Override
- publicbooleanonPreferenceChange(Preferencepreference,ObjectnewValue){
- //TODOAuto-generatedmethodstub
- Log.v("SystemSetting","preferenceischanged");
- Log.v("Key_SystemSetting",preference.getKey());
- //判断是哪个Preference改变了
- if(preference.getKey().equals(updateSwitchKey))
- {
- Log.v("SystemSetting","checkboxpreferenceischanged");
- }
- elseif(preference.getKey().equals(updateFrequencyKey))
- {
- Log.v("SystemSetting","listpreferenceischanged");
- }
- else
- {
- //如果返回false表示不允许被改变
- returnfalse;
- }
- //返回true表示允许改变
- returntrue;
- }
- @Override
- publicbooleanonPreferenceClick(Preferencepreference){
- //TODOAuto-generatedmethodstub
- Log.v("SystemSetting","preferenceisclicked");
- Log.v("Key_SystemSetting",preference.getKey());
- //判断是哪个Preference被点击了
- if(preference.getKey().equals(updateSwitchKey))
- {
- Log.v("SystemSetting","checkboxpreferenceisclicked");
- }
- elseif(preference.getKey().equals(updateFrequencyKey))
- {
- Log.v("SystemSetting","listpreferenceisclicked");
- }
- else
- {
- returnfalse;
- }
- returntrue;
- }
- }
主要是获取xml文件中的各个Preference,然后为其注册监听接口,最后在监听接口的回调函数中打印相关的信息。
接着在Manifest文件中对这个Activity进行注册:
[xhtml] view plain copy print ?
- <activityandroid:name=".Settings">
- </activity>
然后对AndroidPreferenceDemoII.java文件进行如下修改:
[java] view plain copy print ?
- publicclassAndroidPreferenceDemoIIextendsActivity{
- /**Calledwhentheactivityisfirstcreated.*/
- //菜单项
- finalprivateintmenuSettings=Menu.FIRST;
- privatestaticfinalintREQ_SYSTEM_SETTINGS=0;
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- }
- //创建菜单
- @Override
- publicbooleanonCreateOptionsMenu(Menumenu)
- {
- //建立菜单
- menu.add(0,menuSettings,2,"设置");
- returnsuper.onCreateOptionsMenu(menu);
- }
- //菜单选择事件处理
- @Override
- publicbooleanonMenuItemSelected(intfeatureId,MenuItemitem)
- {
- switch(item.getItemId())
- {
- casemenuSettings:
- //转到Settings设置界面
- startActivityForResult(newIntent(this,Settings.class),REQ_SYSTEM_SETTINGS);
- break;
- default:
- break;
- }
- returnsuper.onMenuItemSelected(featureId,item);
- }
- //Settings设置界面返回的结果
- protectedvoidonActivityResult(intrequestCode,intresultCode,Intentdata){
- if(requestCode==REQ_SYSTEM_SETTINGS)
- {
- //获取设置界面PreferenceActivity中各个Preference的值
- StringupdateSwitchKey=getResources().getString(R.string.auto_update_switch_key);
- StringupdateFrequencyKey=getResources().getString(R.string.auto_update_frequency_key);
- //取得属于整个应用程序的SharedPreferences
- SharedPreferencessettings=PreferenceManager.getDefaultSharedPreferences(this);
- BooleanupdateSwitch=settings.getBoolean(updateSwitchKey,true);
- StringupdateFrequency=settings.getString(updateFrequencyKey,"10");
- //打印结果
- Log.v("CheckBoxPreference_Main",updateSwitch.toString());
- Log.v("ListPreference_Main",updateFrequency);
- }
- else
- {
- //其他Intent返回的结果
- }
- }
- }
主要是添加一个设置菜单,点击后转到设置界面,当从设置界面返回后读取保存的内容,并打印出来查看。
最后我们看一下运行的效果:
图9设置界面操作
操作的Log输出如下图10所示:
图10DDMS的LogCat输出
点击设置菜单转到设置界面后,首先点击CheckBox,输出前6行,然后点击ListPreference,输出3行,当选择列表的第二个进行改变时,再输出3行,最后按返回键回到第一个页面,打印出最后2行。
最后我们看一下这些设置参数在系统中的保存文件。在DDMS的FileExplorer中,查看data/data/com.ichliebephone文件夹,我们可以看到有如下文件:
图11Preference保存的文件
把这个文件导出到电脑上,可以看到起内容为:
[xhtml] view plain copy print ?
- <?xmlversion='1.0'encoding='utf-8'standalone='yes'?>
- <map>
- <stringname="auto_update_frequency">30</string>
- <booleanname="auto_update_switch"value="true"/>
- </map>
文件以map的方式保存了两个设置参数
三.总结
我们学习了Android的Preference相关内容,包括最基本的SharedPreferences的使用,及进一步的PreferenceActivity设置界面的介绍,最后根据以上的内容完成了一个简单的Demo。
Preference键值对的方式是Android最简单的一种数据持久化方式,虽然比较简单,但是也比较实用,特别是在保存小量的数据时。Android上的功能更加强大相对也更加复杂的SQLite数据保存方式我们以后接着学习。
续:
重点:分析Preference事件
在PreferenceActivity方法中,一个比较重要的监听点击事件方法为:
publicbooleanonPreferenceTreeClick(PreferenceScreen preferenceScreen,Preference preference)
说明:当Preference控件被点击时,触发该方法。
参数说明: preference点击的对象。
返回值: true 代表点击事件已成功捕捉,无须执行默认动作或者返回上层调用链。例如,不跳转至默认Intent。false 代表执行默认动作并且返回上层调用链。例如,跳转至默认Intent。
在我们继承PreferenceActivity的Activity可以重写该方法,来完成我们对Preference事件的捕捉。
Preference相关的两个重要监听接口。
1Preference.OnPreferenceChangeListener 该监听器的一个重要方法如下:
boolean onPreferenceChange(Preference preference,Object objValue)
说明: 当Preference的元素值发送改变时,触发该事件。
返回值:true 代表将新值写入sharedPreference文件中。false 则不将新值写入sharedPreference文件
2Preference.OnPreferenceClickListener。该监听器的一个重要方法如下:
publicbooleanonPreferenceClick(Preference preference)
说明:当点击控件时触发发生,可以做相应操作。
那么当一个Preference控件实现这两个接口时,当被点击或者值发生改变时,触发方法是如何执行的呢?事实上,
它的触发规则如下:
1先调用onPreferenceClick()方法,如果该方法返回true,则不再调用onPreferenceTreeClick方法 ;
如果onPreferenceClick方法返回false,则继续调用onPreferenceTreeClick方法。
2onPreferenceChange的方法独立与其他两种方法的运行。也就是说,它总是会运行。
下面写个小例子描述下具体实现步骤:
1在res下建立xml文件夹,并在内建立Preference.xml文件。PreferenceScreen是根节点。
<?xmlversion="1.0"encoding="utf-8"?>
<PreferenceScreenxmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/preferences">
<PreferenceScreen
android:key="version"
android:title="@string/about">
</PreferenceScreen>
<PreferenceScreen
android:key="general"
android:title="@string/settings">
<CheckBoxPreference
android:key="auto_start"
android:title="@string/auto_start"/>
<CheckBoxPreference
android:key="keep_screen_on"
android:summary="@string/keep_screen_on_summary"
android:title="@string/keep_screen_on"/>
<CheckBoxPreference
android:key="general_show_icon_in_status_bar"
android:title="@string/show_icon_in_status_bar" />
<PreferenceScreen
android:key="font"
android:title="@string/fonts">
</PreferenceScreen>
<ListPreference
android:key="start_display"
android:title="@string/start_display"
android:summary="Select an option"
android:entries="@array/start_display"
android:entryValues="@array/start_display_entries"
android:dialogTitle="@string/start_display_title"/>
</PreferenceScreen>
</PreferenceScreen>
2在src下建立java文件Preference.java并继承PreferenceActivity。部分结构代码:
publicvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
fonts = (PreferenceScreen) findPreference("font");
startDisplay=(PreferenceScreen)findPreference("start_display");
setFilePath = (PreferenceScreen) findPreference("SetFilePath");
setVolume =(PreferenceScreen) findPreference("SetVolume");
}
3在Preference.java中写事件。可以用Preference的内置控件,也可以在PreferenceScreen中写单击事件。
publicboolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
Preference preference) {
if (preference ==version) { // 版本号
DialogAdapter dialogadapter = new DialogAdapter(this);
dialogadapter.showTipsDialog();
} elseif (preference ==autoStart) { // 开机自启动事件
editor.putBoolean(AUTO_START_STATUS,autoStart.isChecked());
editor.commit();
} elseif (preference ==keepScreenOn) {// 保持屏幕
editor.putBoolean(KEEP_SCREEN_ON,keepScreenOn.isChecked());
editor.commit();
if (keepScreenOn.isChecked()){
AlarmAlertWakeLock.acquireScreenWakeLock(this);
} else {
AlarmAlertWakeLock.release();
}
}
returnsuper.onPreferenceTreeClick(preferenceScreen, preference);
}
看效果:
疑问:
在用listPreference中点击listPreference就开始把上次设置的数据保存在sharePreference中,然而在弹出List中dialog选择时却不会保存,不知道为什么?都最后只能放弃listPreference,自己写事件获得数据。请高人指点!
更多相关文章
- Android通过加载其他应用的Dex文件破解关键数据
- android中javah生成jni头文件报错问题
- Android测试方法总结
- 双击运行Android模拟器、创建SDcard、AVD、安装APK文件、上传文
- SPB Shell 3D:打造最酷3D效果的Android界面
- Android下生成core dump的方法
- Android 使用Thread+Handler实现非UI线程更新UI界面