在Android系统中,当我们点击Menu按钮时,则会弹出Menu的菜单选项,其中一项是设置选项,点击了设置选项后,则会弹出系统的设置 Activity界面,这些设置功能是如何实现的呢?Android系统本身就大量用到了PreferenceActivity来对系统进行信息配置和管理,那么它是怎么保存数据的呢,如何创建PrefenceActivity的呢,更关键是怎样触发相应事件的呢。
Android系统有四种基本的数据保存方法,一是SharedPreference,二是文件,三是SQLite,四是 ContentProvider。PreferenceActivity是如何保存的数据,其实就是通过SharedPreference键值对的形式来保存数据的。
我们以一个例子来说明如何在Android系统中制作一个设置的功能。先看下该例子的大概框架图:
MainActivity.javas是我们的主画面,MyPreferenceActivity.java是设置页面;在res/xml目录下有个mypreference.xml的文件,该文件是设置页面的布局文件,在添加该xml文件的时候,注意是选择的不是 Layout,而是Preference,而且注意Folder路径是 res/xml。
mypreference.xml文件中的代码如下:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<PreferenceCategory
android:key="set_local"
android:title="我的位置" >
<CheckBoxPreference
android:defaultValue="true"
android:key="apply_wifi"
android:summary="使用无线网络在应用程序(例如Google地图)中查看位置"
android:title="使用无线网络" />
<CheckBoxPreference
android:key="apply_gps"
android:summary="定位到街道级别(需要消耗更多的电量以及天气允许)"
android:title="使用GPS" >
</CheckBoxPreference>
<ListPreference
android:key="depart_value"
android:title="部门设置"
android:dialogTitle="部门"
android:entries="@array/department"
android:entryValues="@array/department_value"
android:defaultValue="1"/>
</PreferenceCategory>
</PreferenceScreen>
MyPreferenceActivity.java 的代码如下,该类需要继承PreferenceActivity。()
package com.example.androidtest_preference;
import android.os.Bundle;
import android.preference.PreferenceActivity;
public class MyPreferenceActivity extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.mypreference);
}
}
MainActivity.java的代码如下:
package com.example.androidtest_preference;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends Activity {
private static final int SET = Menu.FIRST;
private static final int EXIT = Menu.FIRST + 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// getMenuInflater().inflate(R.menu.main, menu);
Log.d("MainActivity", "onCreateOptionsMenu");
menu.add(0, SET, 0, "设置");
menu.add(0, EXIT, 0, "退出");
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
Log.d("MainActivity", "onOptionsItemSelected");
switch (item.getItemId()) {
case SET:
Intent intent = new Intent(this,MyPreferenceActivity.class);
startActivity(intent);
break;
case EXIT:
this.finish();
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onOptionsMenuClosed(Menu menu) {
super.onOptionsMenuClosed(menu);
Log.d("MainActivity", "onOptionsMenuClosed");
}
}
array.xml 中的内容如下(该文件中的数组被mypreference.xml引用):
<?xml version="1.0" encoding="utf-8"?>
<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>
同时不要忘记在AndroidManifest.xml文件中加入MyPreferenceActivity.java的配置。
设置画面的运行结果如下:
以上即是使用PrefereneActivity做成设置画面的步骤。
通过PreferenceActivity,我们已经把画面做成了,但是具体该怎么操作数据呢。
Preference类提供了以下两个接口,用于监听Preference的动作。
public interface OnPreferenceChangeListener {
/**
* Called when a Preference has been changed by the user. This is
* called before the state of the Preference is about to be updated and
* before the state is persisted.
*
* @param preference The changed Preference.
* @param newValue The new value of the Preference.
* @return True to update the state of the Preference with the new value.
*/
boolean onPreferenceChange(Preference preference, Object newValue)
当Preference的值被用户改变的时候,该方法被调用。
例如,我们在mypreference.xml 文件中定义的ListPreference的默认值是1.
当用操作ListPreference,选择第二项的时候,该方法就会被调用。
方法的第一个参数就是我们操作的ListPreference的引用,
方法的第二个参数是该Preference的最新值2,(因为我们选择了第二项),
第二项对象的value值为2.
}
/**
* Interface definition for a callback to be invoked when a {@link Preference} is
* clicked.
*/
public interface OnPreferenceClickListener {
/**
* Called when a Preference has been clicked.
*
* @param preference The Preference that was clicked.
* @return True if the click was handled.
*/
boolean onPreferenceClick(Preference preference);
当画面中Preference被点击的时候,调用该方法。
在方法内容我们可以加入自己的逻辑处理。
}
1)通过getPreferenceManager().setSharedPreferencesName(SETTING);
将画面中的preference和那么为SETTTING的Sharepreference关联到一起。
2) 通过【android:key】获取到画面中的preference。
list = (ListPreference) this.findPreference("depart_value");
"depart_value"是在mypreference.xml文件中定义的key值。
3)给Preferenc 设置监听器。
list.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
// 当pfeference的值发生变化的时候,在这里进行处理,将变化后的值
保存在步骤1)中关联到的SharePreferece中。 (具体请参考完整的代码)
如果其他画面加了OnSharedPreferenceChangeListener监听,则能够实时的
接收到通知。
同时在当前画面可以更新preferece的显示信息。 (具体请参考完整的代码)
}
list.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
return true;
}
}
}
修改后的MyPreferenceActivity代码:
package com.example.androidtest_preference;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceActivity;
public class MyPreferenceActivity extends PreferenceActivity {
private ListPreference list = null;
private static final String SETTING = "SETTING";
private static final int DEPATMENT_VALUE = 1;
private static final String DEPATMENT_KEY = "depart_value";
@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 将画面中的preference和那么为SETTTING的Sharepreference关联到一起。
getPreferenceManager().setSharedPreferencesName(SETTING);
addPreferencesFromResource(R.xml.mypreference);
initView();
setViewInfo();
}
private void initView() {
list = (ListPreference) this.findPreference("depart_value");
list.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
// 当Preference的值被用户改变的时候,该方法被调用。
// 例如,我们在mypreference.xml 文件中定义的ListPreference的默认值是1.
// 当用操作ListPreference,选择第二项的时候,该方法就会被调用。
// 方法的第一个参数就是我们操作的ListPreference的引用,
// 方法的第二个参数是该Preference的最新值2,(因为我们选择了第二项),
// 第二项对象的value值为2.
@Override
public boolean onPreferenceChange(Preference preference,
Object newValue) {
// 保存在步骤1)中关联到的SharePreferece中。
SharedPreferences sharedPreferences = getSharedPreferences(
SETTING, Context.MODE_PRIVATE);
Editor editor = sharedPreferences.edit();
// 这里需要注意一下,
// preference.getKey()取得的是mypreference.xml中ListPreference的区别Flg。
// putString 方法的第一个参数是SharedPreferences中某个value的key值。
// 这两个key值的名称必须一致。否则会出现问题。
editor.putString(preference.getKey(), String.valueOf(newValue)).commit();
// 更新当前画面中preference的显示信息。
setViewInfo();
return true;
}
});
// 当画面中Preference被点击的时候,调用该方法。
// 在方法内容我们可以加入自己的逻辑处理。
list.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
return true;
}
});
}
/**
* 从SharedPreferences中取得变化后的信息,更新当前画面中list的Summary显示内容
*/
private void setViewInfo() {
SharedPreferences sharedPreferences = getSharedPreferences(SETTING,Context.MODE_PRIVATE);
String tempDepartValue = sharedPreferences.getString(DEPATMENT_KEY,String.valueOf(DEPATMENT_VALUE));
list.setSummary(tempDepartValue);
}
}
运行效果:
1)默认状态
2)选择第二项后 Summary变为2.
在当前画面中ListPreference的值发生变化后,我们获取到并且设置到SharePreference中。
如果在其他的画面有使用到SharePreference,怎么监听值变化呢?
在其他画面中加入OnSharedPreferenceChangeListener就可以了。