android下配置偏好信息的管理
android下配置偏好信息的管理
佣工7001
应用程序一般都有这样的需求,为了应用有更好的适应性,有一些参数设置需要独立出来放在配置文件里面。这个配置文件应该是开发的时候就编辑好的设好了默认值,安装后应该可以让用户修改一些设置并保存。程序运行的时候读取这些设置并根据设置不同进行不同的操作。比如windows下程序惯用的INI文件,如果是j2ee项目我们会使用property文件来保存这些参数,那么在android下面如何实现呢?在android中提供了SharedPreference这个类来配置参数设置,书上网上很多例子都是用程序对SharedPreference的读写操作,可是怎样拥有初始设置的值呢?当然可以自己读取资源中的xml文件,然后手动写程序保存到SharedPreference中,可这样太麻烦了一点都不方便、不专业。
经过我的一番搜索研究,发现最好的方法就是使用Preference管理设置,android sdk已内置了良好的支持,所有的功能都在android.preference这个命名空间中。经学习发现这个preference的管理是和SharedPreference结合实现的,完美的实现了我的需求,并且是实现了和android系统设置中一样的设置管理界面,显得很专业。闲言少叙,下面就具体来看如何使用preference实现配置功能。
一、建立配置文件。
在项目res目录下xml目录下(如果没有请建立)建立一个settings.xml的xml文件(文件名不一定叫settings,但是一定要放在xml目录下),文件内容如下:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" android:title="Settings" > <PreferenceCategory android:key="general" android:title="基本设置"> <ListPreference android:key="superman" android:entries="@array/choice" android:entryValues="@array/choiceId" android:dialogTitle="我的最爱" android:summary="" android:defaultValue="value5" android:title="你选哪个"/> <CheckBoxPreference android:key="bigman" android:title="我要做大英雄" android:defaultValue="true" android:summaryOn="唯大英雄能本色,是真名士自风流" android:summaryOff="请君暂上凌烟阁,若个书生万户侯"/> <EditTextPreference android:defaultValue="宁可我负天下人,不可天下人负我!" android:key="maxim" android:summary="有了信仰就要干,不要无志者常立志" android:title="我最爱的格言" /> <EditTextPreference android:defaultValue="星球大战" android:key="favoriteFilm" android:summary="没有最好,只有更好" android:title="我最爱的电影" /> </PreferenceCategory> <PreferenceCategory android:key="advanced" android:title="高级设置"> <PreferenceScreen android:key="basicSettings" android:title="高级设置" android:summary="点击进入高级设置" > <CheckBoxPreference android:key="checkVersion" android:title="自动更新" android:defaultValue="false" android:summaryOn="程序将每隔一段时间自动检查新版本" android:summaryOff="自动更新已关闭"/> <EditTextPreference android:defaultValue="1" android:key="checkVersionTime" android:summary="" android:title="检查新版本间隔时间(天)" /> <EditTextPreference android:defaultValue="http://192.168.0.99:8008/crx/xtgl.User" android:key="url" android:summary="" android:title="URL" /> <EditTextPreference android:defaultValue="http://60.29.99.76:8008/crx/xtgl.Unit?__fn_=initdata" android:key="url1" android:summary="" android:title="URL2" /> <EditTextPreference android:defaultValue="htt2.p://192.168.0.100:8558/crx/manage.HistVote" android:key="URL3" android:summary="" android:title="URL3" /> </PreferenceScreen> </PreferenceCategory> </PreferenceScreen>
文件的根元素就是PreferenceScreen,望文生义,就是一个屏幕显示的配置内容,并且可以嵌套使用。PreferenceScreen下面还可以分类,这就是PreferenceCategory元素,并且PreferenceCategory元素下面同样可以嵌套PreferenceScreen元素(其实PreferenceScreen就是PreferenceCategory的子类)。详细的配置内容可用的元素有EditTextPreference,CheckBoxPreference,ListPreference,Preference,RingtongPreference......
从上面的配置文件中可以看出一个Preference配置项目主要拥有的属性。其中Key为这个Preference的ID,设置了才可以在代码中引用,Title是显示的标题,Summary是显示在标题下的文字介绍,Dependency是指依赖的其他配置项(注:一般在Dependency中填写一个CheckBoxPreference的Key,这样就会在填写的那个CheckBoxPreference勾选时当前这个Preference才可用),Default Value为初始值,等等。其他的请大家自己看sdk,在这里就不赘述了。
值得一提的就是ListPreference的使用稍微复杂一些,ListPreference除了继承自Preference的属性外,还有自己ListPreference的属性和继承自DialogPreference的属性。其中属于ListPreference的属性有两个:Entries填的为一个字符串数组,是列表显示出来的值(用户看到的说明文字),而Entry Values是实际要保存的值对应的字符串数组。DialogPreference只要填一个Dialog title标题和一个取消按钮显示的字即可。下面建立两个String array供ListPreference的选择对话框使用,在res/values目录下建立一个新的myarrays.xml文件(文件名随便),内容如下.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="choice">
<item >超人</item>
<item >蜘蛛侠</item>
<item >夜魔侠</item>
<item >青蜂侠</item>
<item >蝙蝠侠</item>
<item >闪电侠</item>
<item >钢铁侠</item>
<item >超胆侠</item>
<item >绿灯侠</item>
</string-array>
<string-array name="choiceId">
<item >value1</item>
<item >value2</item>
<item >value3</item>
<item >value4</item>
<item >value5</item>
<item >value6</item>
<item >value7</item>
<item >value8</item>
<item >value9</item>
</string-array>
</resources>
好了,我们的前期准备已经搞定了。
二、读取配置内容。
配置信息已经建好了,下面就是读取了,怎么读取呢?看到网上的解决方法很简单,就是得到默认的SharedPreference,然后按照Preference的key值读取,好的,马上试验:在Activity中添加一个按钮BtnTestConfig,设置OnClick事件如下:
OnClickListener onBtnTestConfig = new OnClickListener() { public void onClick(View v) { String s = "not read!"; IndexActivity me = IndexActivity.this; SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(me); try { s = sp.getString("favoriteFilm", s); } catch (Exception e) { e.printStackTrace(); } DialogUtil.ShowMsgDlg(IndexActivity.this, String.valueOf(s)); } };
可是一运行发现,显示的是程序中给出的默认值,根本不是配置写的“星球大战”!咋回事儿呢,老办法google一下,发现有说要用XmlResourceParser自己解析XML,可是这就有违初衷了!不行再搜,终于在老外哪里找到了,原来android不会自动将你的Preference配置同步到SharedPreference中,所以需要用到PreferenceManager.setDefaultValues(Context context, int resId, boolean readAgain)方法,修改程序如下:
OnClickListener onBtnTestConfig = new OnClickListener() {
public void onClick(View v) {
String s = "not read!";
IndexActivity me = IndexActivity.this;
PreferenceManager.setDefaultValues(IndexActivity.this, R.xml.settings, true);
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(me);
try {
s = sp.getString("favoriteFilm", s);
} catch (Exception e) {
e.printStackTrace();
}
DialogUtil.ShowMsgDlg(IndexActivity.this, String.valueOf(s));
}
};
再次运行,ok,终于读到了!这里注意PreferenceManager.setDefaultValues方法的第三个参数readAgain,false表示只会执行一次,也就是说SharedPreference已经同步过一次,此函数就不会再执行了,这样如果在调试阶段你会发现新增加的配置项目就读不到了(打开设置界面编辑后是可以的),所以调试时最好用true。当然这里只是试验,在实际程序中,最好放在主Activity中执行这个函数。另外,readAgain设为true,不会覆盖已经存在于SharedPreference中的配置值,不会造成用户修改的配置丢失。
注意,如果你想清除修改的配置,那么在你要这样
PreferenceManager.getDefaultSharedPreferences(Context context),之后调用
PreferenceManager.setDefaultValues(Context context, int resId, boolean readAgain),并且readAgain设为true)
三、实现配置管理界面。
到现在,Preference已经建立好并且可以读取了,那么怎么实现用户修改Preference设置呢?这个就更简单了,新建立一个Activity并继承PreferenceActivity,
public class MyPreference extends PreferenceActivity
然后再onCreate函数中这样写:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.addPreferencesFromResource(R.xml.settings); }
然后要做的就是在主界面中添加菜单或按钮调用这个Activity(这个就赘述了),怎么样,是不是和系统的设置界面一样漂亮。
四、更完美的设置界面。
试了试,搞好的Preference界面,忽然发现了还有一个缺点,每个配置项目下面的Summary信息都是固定的,如果能够显示用户的当前设置那就完美了。废话少说还是网上学习去,过程不必细说,结果发现还真没有方便的手段可用。没办法,只能程序代码实现。所用技术就是Perference.setSummary这个函数。思想就是在初始化的时候,更据当前配置内容,遍历配置项设置summary内容,然后注册SharedPreference的OnSharedPreferenceChangeListener事件监听配置项的变化,随时更新已变化项目的summary信息。
由于需要注册OnSharedPreferenceChangeListener事件,所以我们的Activity还要实现OnSharedPreferenceChangeListener这个接口。
public class MyPreference extends PreferenceActivity implements OnSharedPreferenceChangeListener {
然后添加三个方法:
/** * Set the summaries of all preferences */ private void initSummaries(PreferenceGroup pg) { for (int i = 0; i < pg.getPreferenceCount(); ++i) { Preference p = pg.getPreference(i); if (p instanceof PreferenceGroup) this.initSummaries((PreferenceGroup) p); // recursion else this.setSummary(p); } } /** * Set the summaries of the given preference */ private void setSummary(Preference pref) { // react on type or key if (pref instanceof ListPreference) { ListPreference listPref = (ListPreference) pref; listPref.setSummary(listPref.getEntry()); } if (pref instanceof EditTextPreference) { EditTextPreference etp = (EditTextPreference) pref; etp.setSummary(etp.getText()); } } /** * used to change the summary of a preference */ public void onSharedPreferenceChanged(SharedPreferences sp, String key) { Toast.makeText(this, "preference changed! " + key, 3000); Preference pref = findPreference(key); this.setSummary(pref); }
最后在onCrate方法中添加两行代码:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.addPreferencesFromResource(R.xml.settings); this.getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); this.initSummaries(this.getPreferenceScreen()); }
ok,打完收工,运行起来再看效果:
怎么样,堪称完美吧。下面试试我们的ListPreference,选择一个新的英雄:
选择完成后,再看Preference管理界面,提示信息已变为“夜魔侠”一切ok。