最近,做一个项目,使用 Preference 非常频繁,之前就很想写一些关于 android 数据存储的文章,这次机会来了。
先从小出着手吧,CheckBoxPreference 小巧可爱,使用简单。但是使用的时候,还是需要注意一些问题。下面开始讨论吧,欢迎拍砖!
app 运行之后,效果(很单调):
项目结构图:
这里关键是在 res/ 目录下面新建 xml 文件夹,然后新建我们需要的 Preference 布局(demo.xml)。
demo.xml 文件:
似乎,上面的内容没有什么很难的地方,的确!但是运行 App 之后,你会发现CheckBox 不可以选择?!
在 API 的文档关于 onPreferenceChange 方法中有这么一句:
True to update the state of the Preference with the new value.
可以看出,在这个方法的结尾返回 true 就可以了,呵呵!这点要注意,细节决定效率嘛!
ok,再看第二个问题,我们知道 Preference 可以自动保存状态值,保存是以 xml 文件形式保存的,保存路径在 /data/data/packageName/shared_prefs/×××.xml,但是你到这个路径去找找绝对找不到?!
原因在于我们所写的 demo.xml 文件,在这个文件中,有这么一句:
android:persistent="false"
这就表示不会保存 CheckBoxPreference 这个值(是一个 boolean 值,选择上就是 true,否则就是false)了。
如果,你设置这个属性为 true,android 就会为你自动保存,看下图:
但是为什么会自动保存?为什么文件名称就是 mark.zhang_preference 呢?当然是代码决定的,看源码,就会一目了然了!
当我们点击 CheckBoxPreference 的时候,会触发事件:
protected void onClick() { super.onClick(); boolean newValue = !isChecked(); // in onBindView() an AccessibilityEventViewClickedType is sent to announce the change // not sending mSendAccessibilityEventViewClickedType = true; if (!callChangeListener(newValue)) { return; } setChecked(newValue); }
那麽,
setChecked(newValue)
方法就可以调用,
persistBoolean(checked);
方法,该方法是 Preference 类的方法,然后调用 PreferenceManager 相关的方法获取 SharedPreference 来保存文件。
最后,看一个小问题,就是如何动态获取 CheckBoxPreerence 的值呢?很简单,实现OnSharedPreferenceChangeListener 接口,看代码:
package mark.zhang; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.os.Bundle; import android.preference.CheckBoxPreference; import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.Preference.OnPreferenceChangeListener; import android.preference.Preference.OnPreferenceClickListener; import android.util.Log; public class DemoActivity extends PreferenceActivity implements OnPreferenceClickListener, OnPreferenceChangeListener, OnSharedPreferenceChangeListener { private static final String KEY = "key_cbp"; private CheckBoxPreference cbp = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.demo); cbp = (CheckBoxPreference) findPreference(KEY); cbp.setOnPreferenceClickListener(this); // 注册OnPreferenceChangeListene // cbp.setOnPreferenceChangeListener(this); // 注册 SharedPreferenceChangeListener // 以便回调 onSharedPreferenceChangeListener getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); } @Override public boolean onPreferenceClick(Preference preference) { Log.d("mark", "onPreferenceClick is invoked !"); if (cbp.isChecked()) { // false Log.d("mark", "cbp.isChecked() = " + cbp.isChecked()); } // return true; return false; } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { if (preference.getKey().equals(KEY)) { Log.d("mark", "onPreferenceChange is invoked !" + newValue); // true } // 不可以选择CheckBox // return false; // 可以选择CheckBox return true; } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (key.equals(KEY)) { boolean value = sharedPreferences.getBoolean(key, false); Log.d("mark", "onSharedPreferenceChanged is invoked !" + " and the value = " + value); } } @Override protected void onDestroy() { // 注销 SharedPreferenceChangeListener getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener( this); super.onDestroy(); } }
运行之后,可以看到如下打印信息:
D/mark ( 8077): onSharedPreferenceChanged is invoked ! and the value = false D/mark ( 8077): onPreferenceClick is invoked ! D/mark ( 8077): onSharedPreferenceChanged is invoked ! and the value = true D/mark ( 8077): onPreferenceClick is invoked ! D/mark ( 8077): cbp.isChecked() = true
提醒一点,如果不注册onSharedPreferenceChangListener:
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
是不会回调onSharedPreferenceChanged 方法的。