1.何为首选项(Preference)?
Preference翻译成首选项有点生硬,但似乎也找到不其他更好的翻译,preference在英语的翻译是“偏爱,优先权”的意思。
Android 首选项是用来在Android中读取和存储一些数据,通常是配置项,当然完全还有其他方式能实现,比如数据库或者文件,为什么要使用Android中首选项,个人的理解是一些配置文件存在数据库中还要一张表来存,而且只有一行数据,还要自己写读取和保存方法,实在是累的很。在这提下,Android中的首选项最终是把数据按一定格式存到XMl文件中的,最后我们可以看到,数据的具体样子。
2.看一些今天我们Android首选项的例子效果图(会因为手机主题不同而变化)
主Activity页面 图1 图2 图3
点击主Activity的按钮就会进入图1,如果“喜欢吃水果选款”是勾选状态,下面两个点击就会分别弹出右边的样式,不是勾选状态下面两个就会置灰,不可用。
3. 赶快来看下如何实现的:)
1.首先是preference的布局文件 /res/xml/fruitoptions.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<PreferenceCategory>
<CheckBoxPreference
android:defaultValue="true"
android:key="@string/love_fruit_pref"
android:summary="@string/love_fruit_summary"
android:title="@string/love_fruit_title" />
</PreferenceCategory>
<PreferenceCategory android:key="@string/detailSetting" >
<ListPreference
android:defaultValue="@string/fruit_option_default_value"
android:dialogTitle="@string/dialogTitle"
android:entries="@array/fruit_options"
android:entryValues="@array/fruit_options_values"
android:key="@string/selected_fruit_option"
android:summary="@string/listSummary"
android:title="@string/listTitle" />
<EditTextPreference
android:dialogTitle="@string/customed_fruit_dialogTitle"
android:key="@string/customed_fruit_pref"
android:summary="@string/customed_fruit_summary"
android:title="@string/customed_fruit_title" />
</PreferenceCategory>
</PreferenceScreen>
注意:
/res/xml/fruitoptions.xml文件还需要
/res/values/strings.xml和
/res/values/arrays.xml支持
想尽可能多的把所有preference都举例出,所以这个xml文件中包含了CheckBoxPreference,ListPreference,EditTextPreference,当然还有RingtonePreference没有举例出,留给读者自己研究。
CheckBoxPreference,ListPreference,EditTextPreference,三个东西都有很多属性android:key,android:title等,android:key有点像普通控件中的android:id。
其他ListPreference中的android:entries 是列表项要显示出的文本,android:entryValues是列表项的键或者值,其他属性都是描述性的,大家可以根据字面英文意思来理解。
需要注意的是这个布局文件中用到了PreferenceScreen和PreferenceCategory。
PreferenceScreen是一些配置的集合,会在一个独立的屏幕中显示,大家可以试一下嵌套的PreferenceScreen,点击后会弹出一个新的屏幕
PreferenceCategory 正如我们图1中显示的那样,会有一个独立的外框来分开。
2.接下来是 /res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, PreferenceDemoActivity!</string>
<string name="app_name">PreferenceDemo</string>
<string name="selected_fruit_option">selected_fruit_option</string>
<string name="fruit_option_default_value">1</string>
<string name="prefTitle">Preference 示例</string>
<string name="listTitle">选择一个水果</string>
<string name="dialogTitle">选择一个水果</string>
<string name="listSummary"></string>
<string name="btnText">点击打开配置</string>
<string name="detailSetting">detailSetting</string>
<string name="love_fruit_pref">like_fruit_pref</string>
<string name="love_fruit_title">喜欢吃水果?</string>
<string name="love_fruit_summary">喜欢吃水果的话就勾选此项:)</string>
<string name="customed_fruit_pref">customed_fruit_pref</string>
<string name="customed_fruit_title">你自己喜欢的水果?</string>
<string name="customed_fruit_summary">上面的还不够,写下你喜欢的:)</string>
<string name="customed_fruit_dialogTitle">我喜欢的水果</string>
</resources>
3.最后是/res/values/arrays.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="fruit_options">
<item>苹果</item>
<item>葡萄</item>
<item>橘子</item>
</string-array>
<string-array name="fruit_options_values">
<item>0</item>
<item>1</item>
<item>2</item>
</string-array>
</resources>
用@string/xxxx的方式来显示文字除了可以很容易的支持多种语言外还有很多好处,在获取key的时候也不需要打字符串,可以从strings.xml文件中读取,也不容易错。
4.好了到我们主Activity的布局代码了 /res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="@+id/btnOpenSetting"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/btnText" />
<TextView
android:id="@+id/result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
很简单,一个按钮,一个显示我们的结果。
Activity的代码部分 PreferenceDemoActivity.java
package com.waitingfy.android;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class PreferenceDemoActivity extends Activity {
private Button btnOpenSetting;
private TextView resutlTextView;
private SharedPreferences prefs;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
/* 两种方式获得 SharedPreferences */
// prefs = getSharedPreferences("com.waitingfy.android_preferences", 0);
prefs = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext());
btnOpenSetting = (Button) findViewById(R.id.btnOpenSetting);
resutlTextView = (TextView) findViewById(R.id.result);
// 按钮绑定点击监听
btnOpenSetting.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent();
intent.setClass(getApplicationContext(),
com.waitingfy.android.FruitPreferenceActivity.class);
startActivityForResult(intent, 0);
}
});
setOptionText();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
setOptionText();
}
/*
* 从首选项中获得值,给控件赋值
*/
private void setOptionText() {
StringBuilder resultString = new StringBuilder();
Resources resources = this.getResources();
// 从checkboxPreference获得值
Boolean isLove = prefs.getBoolean(
resources.getString(R.string.love_fruit_pref), true);
// 从listPreference获得值
String selectFruit = prefs.getString(
resources.getString(R.string.selected_fruit_option),
resources.getString(R.string.fruit_option_default_value));
// 从 EditTextPreference获得值
String customedFruit = prefs.getString(
resources.getString(R.string.customed_fruit_pref), "");
resultString.append(isLove.toString() + ",");
resultString.append(selectFruit + ",");
resultString.append(customedFruit);
resutlTextView.setText(resultString);
}
}
都有注释,应该问题不大。
需要解析下的是有两种方法都可以得到SharedPreferences的实例
1. SharedPreferences prefs = getSharedPreferences("com.waitingfy.android_preferences", 0);
2. SharedPreferences
要从一个复选框首选项(CheckBoxPreference)中读取值用getBoolean()方法,将key传递给它就可以了,从ListPreference或EditPreference中读取值用getString(),也是传递一个key.
5.最后我们来看下载入首选项界面的代码是如何的FruitPreferenceActivity.java
通过这个代码我们就可以知道如何对首选项中的控件进行操作,不单单是读取他们的值。
package com.waitingfy.android;
import android.content.res.Resources;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
public class FruitPreferenceActivity extends PreferenceActivity {
private CheckBoxPreference checkBoxPreference;
private PreferenceCategory preferenceCategory;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 从资源中添加preferences
addPreferencesFromResource(R.xml.fruitoptions);
Resources resources = this.getResources();
//使用findpreference根据key返回特定的preference
checkBoxPreference = (CheckBoxPreference) findPreference(resources
.getString(R.string.love_fruit_pref));
preferenceCategory = (PreferenceCategory) findPreference(resources
.getString(R.string.detailSetting));
//checkbox绑定点击事件
checkBoxPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
return SetPrefCategoryStateByCheckBoxState();
}
});
SetPrefCategoryStateByCheckBoxState();
}
/*
* 根据checkbox的状态改变一个prefcategory的状态
* */
private boolean SetPrefCategoryStateByCheckBoxState() {
if(checkBoxPreference.isChecked()){
preferenceCategory.setEnabled(true);
return true;
}else {
preferenceCategory.setEnabled(false);
return false;
}
}
}
代码也很清晰,主要是点击Checkboxpreference时我们要实现图1中下面两个选项的置灰效果,我们使用了findPreference,这个有点像findVIewById,只是这里传递进去的是key,不是Id,其他如Listpreference也可以通过findPreference来获取。
6.最后是我们的AndroidMinifest.xml文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.waitingfy.android"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".PreferenceDemoActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".FruitPreferenceActivity">
<intent-filter>
<action android:name="com.waitingfy.android.FruitPreferenceActivity"/>
<category android:name="android.intent.category.PREFERENCE"/>
</intent-filter>
</activity>
</application>
</manifest>
AndroidMinifest.xml中只要注册两个Activity就行了,第二个Activity有个category可以关注下
7. 最后来看下我们数据存储的位置:
在/data/data/应用程序包名称/shared_prefs下
里面的内容:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="selected_fruit_option">2</string>
<boolean name="like_fruit_pref" value="false" />
<string name="customed_fruit_pref">桃子</string>
</map>
好了,到这里这个Android首选项的示例就结束了,参考的是《精通Android2》的11章。
附上示例下载地址:PreferenceDemo