Android之Preference
2012-08-20 19:32 ...平..淡... 阅读(1332) 评论(0) 编辑 收藏 举报首先介绍下什么是 PerferenceActivity,看下面的截图:
Android系统截图 MusicPlayer Setting截图
Android系统本身大量用到了PreferenceActivity来对系统进行信息配置和管理。那么它是怎么保存数据的呢,如何创建PrefenceActivity的呢,更关键是怎样触发相应事件的呢?
第一个问题:PreferenceActivity是如何保存的数据。
Android系统有四种基本的数据保存方法:
1.SharedPreference
2.文件
3.SQLite
4.ContentProvider
Preference,其实是通过SharedPreferneces以键值对的形式进行保存的,当然,我们也可以通过SharedPreferences来获取PreferenceActivity设置的值。
第二个问题:如何创建一个PreferenceActivity。 其实Eclipse提供了相应的创建工具,和创建Layout是基本相同的。步骤如下:
创建Android项目,并添加一个Android xml文件。注意,这次选择的不是Layout,而是Preference,而且注意Folder路径是 res/xml
添加完成之后,在res/xml/下打开添加的preference.xml文件。可以看到Android也为我们提供两种编辑模式,可视化的结构设计及xml源码设计。推荐使用structure进行创建。如图所示:
下面我们看看PrefeneceActivity都提供了哪几种元素可供使用。点击Add按钮,在打开的新窗口中可以看到以下几项:
下面,我们对比Preference和View下的各个子控件,对他们的家庭元素在宏观上有更好的把握性。
单一控件: Preference 控件家庭 View控件家庭 控件含义 Preference TextView 文本框 CheckPreference CheckBox 单选框 EditTextPreference EditText 输入文本框 ListPreference ListView 列表框 RingtonePreference —— 铃声 其实在Android源码系统中还有很多的”未完工”的Preference, 没有为它们提供PI接口,例如SeekBarPreference, 有兴趣的同学可以参考源码,具体路径为:frameworks/base/core/java/preference。 组合控件: PreferenceCategory : 类似于LinearLayout、RelativeLayout,用于组合一组Preference,使布局更具备层次感。 PreferenceScreen : 所有Preference元素的根节点。
接下来,对每个Preference的独有XML Attributes和方法进行一下总结,使大家能更好地理解。
CheckBoxPreference:CheckBox选择项,对应的值的ture或flase。如图:
EditTextPreference:输入编辑框,值为String类型,会弹出对话框供输入。
ListPreference: 列表选择,弹出对话框供选择。
Preference:只进行文本显示,需要与其他进行组合使用。
PreferenceCategory:用于分组。效果如下:
PreferenceScreen:PreferenceActivity的根元素,必须为它。
RingtonePreference:系统玲声选择。
OK,Preference的基本控件和PreferenceActivity介绍完毕,下一节对Preference的各个控件的属性方法等做一个介绍。
---------------------------------------------------------------------------------------------------------------
首先了解Preference的属性及方法
Preference元素的通用XML Attributes说明: android:key :每个Preference控件独一无二的”ID”,唯一表示此Preference。 android:defaultValue : 默认值。 例如,CheckPreference的默认值可为”true”,默认为选中状态;EditTextPreference的默认值可为”110” 。 android:enabled : 表示该Preference是否可用状态。
android:title : 每个Preference在PreferenceScreen布局上显示的标题——大标题
android:summary : 每个Preference在PreferenceScreen布局上显示的标题——小标题(可以没有)
android:persistent : 表示Preference元素所对应的值是否写入sharedPreferen文件中,如果是true,则表示写入;否则,则表示不写入该Preference元素的值。
android:dependency : 表示一个Preference(用A表示)的可用状态依赖另外一个Preference(用B表示)。B可用,则A可用;B不可用,则A不可用。
android:disableDependentsState: 与android:dependency相反。B可用,则A不可用;B不可用,则A可用。
常用的方法则包括:
getKey() setKey()
getSummary() setSummary()
getText() setText()
简易效果图
下面通过分析MusicPlayer Setting来了解各个Preference控件的使用。
第一部分为“我的位置”:包括“使用无线网线”和“使用GPS”两个部分,而且都是CheckBox,根据上节学习,应该包括一个PreferenceCategory和两个CheckBoxPreference。
Xml代码:
<PreferenceCategory android:title="我的位置" android:key="set_local"> <CheckBoxPreference android:key="apply_wifi" android:summary="使用无线网络在应用程序(例如Google地图)中查看位置" android:title="使用无线网络" android:defaultValue="true"> </CheckBoxPreference> <CheckBoxPreference android:key="apply_gps" android:summary="定位到街道级别(需要消耗更多的电量以及天气允许)" android:title="使用GPS"> </CheckBoxPreference> </PreferenceCategory>
PreferenceCategory属性分析:
android:title:显示的标题
android:key :唯一标识(至少在同一程序中是唯一),SharedPreferences也将通过此Key值进行数据保存,也可以通过key值获取保存的信息 (以下相同)。
CheckBoxPreference属性分析:
android:Key :唯一标识.
android:title :显示标题(大字体显示)
android:summary :副标题(小字体显示)
android:defaultValue:默认值(当然,此处只能是true或false了)
Preference.xml的第二部分为"无线和网络设置",此部分包括的内容比较多,也稍微复杂,一步一步来分析。xml代码如下:
<PreferenceCategory android:title="无线和网络设置">
<CheckBoxPreference
android:key="apply_fly"
android:summary="禁用所有无线连接"
android:title="飞行模式"> </CheckBoxPreference>
<CheckBoxPreference
android:key="apply_internet"
android:summary="禁用通过USB共享Internet连接" android:title="Internet共享"> </CheckBoxPreference>
<CheckBoxPreference
android:key="apply_wifi"
android:summary="打开Wi-Fi"
android:title="Wi-Fi"> </CheckBoxPreference>
<Preference
android:summary="设置和管理无线接入点"
android:title="Wi-Fi设置"
android:dependency="apply_wifi"
android:key="wifi_setting"> </Preference>
<CheckBoxPreference
android:key="apply_bluetooth"
android:summary="启用蓝牙"
android:title="蓝牙"> </CheckBoxPreference>
<Preference
android:summary="管理连接、设备设备名称和可检测性"
android:title="蓝牙设置"
android:dependency="apply_bluetooth"
android:key="bluetooth_setting"> </Preference>
<EditTextPreference
android:key="number_edit"
android:title="输入电话号码"> </EditTextPreference>
<ListPreference
android:title="部门设置"
android:entries="@array/department" android:entryValues="@array/department_value" android:dialogTitle="选择部门" android:key="depart_value"> </ListPreference>
<RingtonePreference
android:ringtoneType="all"
android:title="玲聲" android:showDefault="true"
android:key="ring_key" android:showSilent="true"> </RingtonePreference>
</PreferenceCategory>
第二部分中前三个都为CheckBoxPreference,不心多说,从<Preference android:key="bluetooth_setting"/>开始。
Preference 属性分析:
android :Key:唯一标识.
android:title :显示标题(大字体显示)
android:summary :副标题(小字体显示)
android:dependency:附属,即标识此元素附属于某一个元素(通常为CheckBoxPreference),dependency值为所附属元素的key。上面代码中的Preference元素附属于key等于"apply_bluetooth"的CheckPreference元素,当CheckPreference值为true时,Preference则为可用,否则为不可用。
EditTextPreperence 属性和方法分析:
属性:
android:Key :唯一标识. android:title:显示标题(大字体显示)
方法:
getEditText() 返回的是我们在该控件中输入的文本框值
getText() 返回的是我们之前sharedPreferen文件保存的值
ListPreference 属性和方法分析:
属性:
android:Key :唯一标识.
android:title :显示标题(大字体显示)
android:dialogTitle:弹出对话框的标题
android:entries :列表中显示的值。为一个数组,通读通过资源文件进行设置。
android:entryValues:列表中实际保存的值,也entries对应。为一个数组,通读通过资源文件进行设置。以下代码显示的是arrays.xml文件中内容:
<resources> <string-array name="department"> <item>综合部</item> <item>行政部</item> <item>外贸部</item> </string-array> <string-array name="department_value"> <item>001</item> <item>002</item> <item>003</item> </string-array> </resources>
方法:
CharSequence[] getEntries(): 返回的是控件显示文本的一个”key”数组,对应于属性android:entries
CharSequence[] getEntryValues():返回的一个”value”数组,对应于属性android: entryValues
CharSequence getEntry(): 返回当前选择文本
String getValue() :返回当前选中文本选中的value 。
RingtonePreference属性分析:
属性: android:ringtoneType:响铃的铃声类型,主要有:ringtone(音乐)、notification(通知)、alarm(闹铃)、all(所有可用声 音类型)。 android:showDefault :默认铃声,可以使用系统(布尔值---true,false)的或者自定义的铃声 android:showSilent :指定铃声是否为静音。指定铃声包括系统默认铃声或者自定义的铃声
OK,Preference.xml内容已经分析完毕,属性都大致相同。
--------------------------------------------------------------------------
那么如何把Preference.xml中内容展现出来呢?
PreferenceActivity是专门用于显示preference的,所以只要创建一个继承自PreferenceActivity类即可。代码如下,在onCreate方法中通过addPreferencesFromResource()实现:
1 public class Setting extends PreferenceActivity { 2 @Override 3 public void onCreate(Bundle savedInstanceState) { 4 super.onCreate(savedInstanceState); 5 // 所的的值将会自动保存到SharePreferences 6 addPreferencesFromResource(R.xml.preference); 7 } 8 }
接下来就是运行程序,显示劳动成果。至此,工作已经完成大半,所有的值都会保存到SharedPreferences中,我们也可以读取到保存的结果。
重点:分析Preference事件
那么,如何响应PreferenceActivity的操作。其实只要重写PreferenceActivity的 onPreferenceTreeClick方法就可以了,通过参数preference来判断是对那一个元素进行的,并根据需要进行操作。
★在PreferenceActivity方法中,一个比较重要的监听点击事件方法为: public booleanonPreferenceTreeClick (PreferenceScreen preferenceScreen, Preference preference) 说明 : 当Preference控件被点击时,触发该方法。
参数说明: preference 点击的对象。 返回值 : true 代表点击事件已成功捕捉,无须执行默认动作或者返回上层调用链。 例如,不跳转至默认Intent。 false 代表执行默认动作并且返回上层调用链。例如,跳转至默认Intent。 在我们继承PreferenceActivity的Activity可以重写该方法,来完成我们对Preference事件的捕捉。
相信通过前面的介绍,你一定知道了如何使用了Preference家族并且对其触发方法。下面我们抛出另外两枚炸弹——Preference相关的两个重要监听接口。
★ Preference.OnPreferenceChangeListener 该监听器的一个重要方法如下: boolean onPreferenceChange(Preference preference,Object objValue) 说明 :当Preference的元素值发送改变时,触发该事件。 返回值:true 代表将新值写入sharedPreference文件中。 false 则不将新值写入sharedPreference文件
★ Preference.OnPreferenceClickListener 该监听器的一个重要方法如下: public booleanonPreferenceClick(Preference preference) 说明:当点击控件时触发发生,可以做相应操作。
那么当一个Preference控件实现这两个接口时,当被点击或者值发生改变时,触发方法是如何执行的呢?事实上,
它的触发规则如下:
1 先调用onPreferenceClick()方法,
(1) 如果该方法返回true,则不再调用onPreferenceTreeClick方法 ;
(2) 如果onPreferenceClick方法返回false,则继续调用onPreferenceTreeClick方法。
2 onPreferenceChange的方法独立与其他两种方法的运行。也就是说,它总是会运行。
到此关于PreferenceActvity和Preference的分析基本结束。
--------------------------------------------------------------------
获取配置信息
1 /** 2 * 获取是否播放声音 3 */ 4 public static boolean playSounds(Context context) { 5 return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SOUNDS, SOUNDS_DEFAULT); 6 } 7 8 /** 9 * 设置播放的声音 10 * @param context 上下文 11 * @param value 是否播放 12 */ 13 public static void setPlaySounds(Context context, boolean value) { 14 PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(SOUNDS, value).commit(); 15 } 16 17 /** 18 * 获取警告时间 19 * @param context 上下文 20 * @return 警告时间秒 21 */ 22 public static int getWarningTime(Context context) { 23 String value=PreferenceManager.getDefaultSharedPreferences(context).getString(WARNING_TIME,Integer.toString(WARNING_TIME_DEFAULT)); 24 try 25 { 26 return Integer.parseInt(value); 27 } 28 catch(NumberFormatException e) 29 { 30 setWarningTime(context, WARNING_TIME_DEFAULT); 31 return WARNING_TIME_DEFAULT; 32 } 33 34 } 35 36 /** 37 * 设置警告时间 38 * @param context 上下文 39 * @param warningTime 警告时间 40 */ 41 public static void setWarningTime(Context context, int warningTime) { 42 PreferenceManager.getDefaultSharedPreferences(context).edit().putString(WARNING_TIME, Integer.toString(warningTime)).commit(); 43 44 } 45 46 /** 47 * 参加人数无限制 48 * @param context 49 * @return 50 */ 51 public static boolean allowUnlimitedParticipants(Context context) { 52 return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(UNLIMITED_PARTICIPANTS, UNLIMITED_PARTICIPANTS_DEFAULT); 53 } 54 55 public static void setAllowUnlimitedParticipants(Context context, boolean value) { 56 PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(UNLIMITED_PARTICIPANTS, value).commit(); 57 } 58 59 /** 60 * 允许编辑会议时间 61 * @param context 62 * @return 63 */ 64 public static boolean allowVariableMeetingLength(Context context) { 65 return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(VARIABLE_MEETING_LENGTH, VARIABLE_MEETING_LENGTH_DEFAULT); 66 } 67 68 public static void setAllowVariableMeetingLength(Context context, boolean value) { 69 PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(VARIABLE_MEETING_LENGTH, value).commit(); 70 }
Preferencescreen的应用:它不仅可以作为设置界面显示,而且还能够启动activity,下面主要是对启动activity的介绍
1. Preferencescreen中启动activity
例如wireless_setting.xml中有如下片段
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:settings="http://schemas.android.com/apk/res/com.seedshope.android"> <PreferenceScreen android:key="wifi_settings" android:title="@string/wifi_settings" android:summary="@string/wifi_settings_summary" > <intent android:action="android.intent.action.MAIN" android:targetPackage="com.android.settings" android:targetClass="com.android.settings.wifi.WifiSettings" /> </PreferenceScreen> </PreferenceScreen>
其中com.android.settings是工程的包名,com.android.settings.wifi.WifiSettings是要启动的类。
一般情况下这样就ok了,点击对应的Preference就能启动对应的activity,然而仅仅这样,并不一定能够启动对应的activity,因为它与回调函数onPreferenceTreeClick有关,有时候我们会重写这个方法如:
1 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { 2 if ( (preference == mAirplaneModePreference) && (Boolean.parseBoolean(SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) ) { 4 // In ECM mode launch ECM app dialog 5 startActivityForResult( new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null), REQUEST_CODE_EXIT_ECM); 8 return true; 9 } 10 else { 11 // Let the intents be launched by the Preference manager 12 return false; 13 } 14 }
其中WirelessSetting.java中有如上函数,当返回值为true时,你怎么点击Preference都不会跳转到activity的,只有等到它的返回值为false的时候,才可以正常跳转,因为点击某一个Preference的真正实现在Preference.java的performClick函数中如下:
1 void performClick(PreferenceScreen preferenceScreen) { 2 if (!isEnabled()) { 3 return; 4 } 5 onClick(); 6 if (mOnClickListener != null && mOnClickListener.onPreferenceClick(this)) { 7 return; 8 } 9 PreferenceManager preferenceManager = getPreferenceManager(); 10 if (preferenceManager != null) { 11 PreferenceManager.OnPreferenceTreeClickListener listener = preferenceManager.getOnPreferenceTreeClickListener(); 12 if (preferenceScreen != null && listener != null && listener.onPreferenceTreeClick(preferenceScreen, this)) { 13 return; 14 } 15 } 16 if (mIntent != null) { 17 Context context = getContext(); 18 context.startActivity(mIntent); 19 } 20 }
当点击某个Preference时的调用流程是
AdapterView.performItemClick--->PreferenceScreen.onItemClick--->Preference.performClick--->PreferenceActivity.onPreferenceTreeClick
当onPreferenceTreeClick返回true的时候就直接return了,没有走下面启动activity的地方了,因此要使一个Preference能够正常跳转到另外一个activity有两个条件,
1.xml里面是否设置正确
2.调用该xml的java类是否在onPreferenceTreeClick这个函数需要返回false
转自:
http://blog.csdn.net/qinjuning/article/details/6710003
http://www.cnblogs.com/joey-home/archive/2012/02/03/2336778.html