SharedPreferences
应用开发中常常需要保存一些简单的状态,比如时间、开关状态等,使用数据库有点大材小用,Android系统有专门的数据结构用来保存简单的数据:SharedPreferences。通常配合设置界面保存各种设置项状态,详见《PreferenceScreen 设置项》及《PreferenceFragmentCompat 设置界面》。
1、SharedPreferences
SharedPreferences是轻量级的存储类,主要是保存一些小的数据,一些状态信息。
1.1、SharedPreferences介绍
从API Level 1就提供的系统工具。提供了很多简单易用的API,方便开发者调用读写数据。但是!SharedPreferences为了保证全局读写的唯一性,即有可能阻塞主线程早ANR。这种情况线上遇到的太多了。
1.2、SharedPreferences读写模式
SharedPreferences有四种MODE可选,
①MODE_PRIVATE:只能被自己的应用访问,是默认的MODE,推荐!
②MODE_WORLD_READABLE:可以被其它应用读取
③MODE_WORLD_WRITEABLE:可以被其它应用读写
④MODE_MULTI_PROCESS:提供跨进程访问的功能
定义的源码如下:
/** @hide */
@IntDef(flag = true, prefix = { "MODE_" }, value = {
MODE_PRIVATE,
MODE_WORLD_READABLE,
MODE_WORLD_WRITEABLE,
MODE_MULTI_PROCESS,
})
@Retention(RetentionPolicy.SOURCE)
public @interface PreferencesMode {}2、获取SharedPreferences
目前有三种途径获取SharedPreferences对象。
2.1、通过Context
Context提供了操作SharedPreferences的三个方法
①创建指定名称的SP
//指定名称,保存成name.xml中
getSharedPreferences("name", Context.MODE_PRIVATE);②删除指定名称的SP
boolean deleteSharedPreferences(String name)③SP迁移,数据从原Context上下文迁移到调用上下文Context中
boolean moveSharedPreferencesFrom(Context sourceContext, String name)2.2、通过Activity()(不推荐)
在Activity可以发现多一个方法getPreferences(int mode),只需要指定读写mode即可
//默认当前Activity名
getPreferences(Context.MODE_PRIVATE);查看源码可以看见,默认了SP名为当前Activity类名。
public SharedPreferences getPreferences(@Context.PreferencesMode int mode) {
return getSharedPreferences(getLocalClassName(), mode);
}因为Activity继承自Context所以Context中的方法都可以使用。
2.3、通过PreferenceManager(不推荐)
①获取默认的SharedPreference
//deprecated,不推荐
PreferenceManager.getDefaultSharedPreferences(this);查看PreferenceManager源码:
public static SharedPreferences getDefaultSharedPreferences(Context context) {
return context.getSharedPreferences(getDefaultSharedPreferencesName(context),
getDefaultSharedPreferencesMode());
}
//获取默认MODE,就是MODE_PRIVATE
private static int getDefaultSharedPreferencesMode() {
return Context.MODE_PRIVATE;
}
//默认SP名就是:包名_preferences
public static String getDefaultSharedPreferencesName(Context context) {
return context.getPackageName() + "_preferences";
}②获取默认SP名就是:包名_preferences
//获取当前SharedPreference的XML文件名称
PreferenceManager.getDefaultSharedPreferencesName(this);3、读写操作
SP提供了简单的API读写数据。
3.1、读
从SharedPreferences直接读数据,有如下一些方法:
①Map<String, ?> getAll()
②boolean getBoolean(String key, boolean defValue)
③float getFloat(String key, float defValue)
④long getLong(String key, long defValue)
⑤String getString(String key, @Nullable String defValue)
⑥Set<String> getStringSet(String key, @Nullable Set<String> defValues)
例:
sharedPreferences.getString("name", "Quibbler");
sharedPreferences.getInt("age", 26);
sharedPreferences.getBoolean("is", false);3.2、写
写数据到SharedPreferences需要借助SharedPreference.Editor,而且方法都会返回当前Editor,方便使用链式调用一次写完。关于apple()和commit()的详细区别详见《源码理解apply()与commit()的区别》。
①Editor putString(String key, @Nullable String value)
②Editor putStringSet(String key, @Nullable Set<String> values)
③Editor putInt(String key, int value)
④Editor putLong(String key, long value)
⑤Editor putFloat(String key, float value)
⑥Editor putBoolean(String key, boolean value)
⑦Editor remove(String key):移除指定key对应的值
⑧Editor clear():清空数据
⑨boolean commit():立即提交数据到存储
⑩void apply():先写入内容,最后写到磁盘
例:
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean("is", true);
editor.putString("name", "QUIBBLER");
editor.putInt("age", 25);
editor.apply(); //异步先提交到内存中
//或者
editor.commit(); //同步写到存储,耗时4、监听
查看源码的时候发了还有监听SharedPreferences变化的监听器接口OnSharedPreferenceChangeListener
public interface OnSharedPreferenceChangeListener {
/**
* 更改,添加或删除共享首选项时调用。
* 即使将首选项设置为其现有值,也可以调用此方法。
* 该回调将在主线程上运行。
*
* @param sharedPreferences The {@link SharedPreferences} that received the change.
* @param key 已更改,添加或删除的首选项的键。
*/
void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key);
}并且提供了注册和反注册监听器的方法:
①registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener)
②unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener)
注意:SharedPreferences当前不存储对侦听器的强引用。您必须存储对侦听器的强引用,否则将容易受到垃圾回收的影响。我们建议您在需要侦听器的对象的实例数据中保留对侦听器的引用。
5、注意
SharedPreferences及时读写操作到放到子线程,及时使用apply()异步提交,即使不大量的写入数据也会出问题,可能阻塞主线程,严重的时候会导致ANR。
①即使在子线程读写,当Activity opPause等情况发生时,会强制写入全部数据任务。如果apply()提交到任务队列的任务过多,主线程会阻塞等待。
②即使每次只修改一个key,也会写一遍全部的文件。所以SP文件一定不能太大,保存很多key,一般50个都已经很多了!
③不要想着使用SP跨进程保存一些状态给其它进程读!
相关资料:
Docs > Reference > SharedPreferences">Android Developers > Docs > Reference > SharedPreferences
Android SharedPreferences使用以及原理详解

