文章目录
简介
SharedPreference 是一个轻量级的 key-value 存储框架,SharedPreference的具体实现与每个应用的上下文环境有关,每个应用有自己的单独的文件夹存放这些数据,对其他应用不可见。
SharedPreference文件都是默认存放在/data/data/< package name>/shared_prefs/目录下的
使用步骤
(1)得到SharePreference对象
-
Context类中获取SharedPreference获取对象的方式(线程安全)
如果需要多个由名称标识的(SharedPreference)共享偏好的设置文件,使用这种构造方式,第一个参数为文件名称(没有文件就会创建一个),第二个参数用于指定操作模式,MODE_PRIVATE代表只有当前应用程序才能对此文件进行读写操作,目前其他模式已经被废除。
SharedPreferences sharedPreferences = getSharedPreferences("Student",MODE_MULTI_PROCESS);
- Activity类中获取SharedPreference的方式
如果只需要使用Activity的SharedPreference由于这会检索属于该 Activity 的默认共享偏好设置文件因此无需提供名称。会默认将当前活动的类名作为文件名,就可以使用下面这种构造方式,这种方式底层实现就是将第一个参数设置为getLocalClassName
sharedPreferences = getPreferences(MODE_PRIVATE);
(2)调用SharedPreference对象的edit()方法获取一个SharedPreferences.Editor对象
(3)向SharedPreferences.Editor对象中添加数据,putXXX();
(4)调用apply()方法将添加的数据提交,从而完成数据存储操作。
源码分析
获取SharedPreferences对象的过程
Context是一个抽象类,它的子类中有ContextImpl和ContextWrapper
Context mBase;
public SharedPreferences getSharedPreferences(String name, int mode) {
//这里其实调用的是ContextImpl的getSharedpreferences方法
return mBase.getSharedPreferences(name, mode);
}
最终还是要看看ContextImpl中的getSharedPreferences的具体实现:
public SharedPreferences getSharedPreferences(String name, int mode) {
//当SDK< 19时,如果文件名为null则会初始化名字为"null"
if (mPackageInfo.getApplicationInfo().targetSdkVersion <
Build.VERSION_CODES.KITKAT) {
if (name == null) {
name = "null";
}
}
File file;
synchronized (ContextImpl.class) {
//建立了文件名和File文件的一一对应关系
if (mSharedPrefsPaths == null) {
mSharedPrefsPaths = new ArrayMap<>();
}
file = mSharedPrefsPaths.get(name);
if (file == null) {
//在相应的sharedPreference下新建File,保存文件名为XXX.xml
file = getSharedPreferencesPath(name);
mSharedPrefsPaths.put(name, file);
}
}
return getSharedPreferences(file, mode);
}
新建File的缓存,使用Map建立了文件名和File文件的一一对应,如果没有文件则新建,并放入Map中,如果Map中有需要的文件,则直接使用get方法取出。最终调用了ContextImpl的getSharedPreferences方法。
public SharedPreferences getSharedPreferences(File file, int mode) {
SharedPreferencesImpl sp;
synchronized (ContextImpl.class) {
//在每个包下面建立了一个File-SharedPreferencesImpl对应关系的ArrayMap
//getSharedPreferencesCacheLocked()根据包名返回相对应包下的ArrayMap
final ArrayMap<File, SharedPreferencesImpl> cache = getSharedPreferencesCacheLocked();
//从file-SharedPreferencesImpl键值对中根据当前file找到SharedPreferencesImpl实例
sp = cache.get(file);
//如果没有对应的SharedPreferencesImpl,就新建一个
if (sp == null) {
// 检查mode,如果是MODE_WORLD_WRITEABLE或者MODE_MULTI_PROCESS则直接抛异常
checkMode(mode);
if (getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.O) {
if (isCredentialProtectedStorage()
&& !getSystemService(UserManager.class)
.isUserUnlockingOrUnlocked(UserHandle.myUserId())) {
throw new IllegalStateException("SharedPreferences in credential encrypted "
+ "storage are not available until after user is unlocked");
}
}
sp = new SharedPreferencesImpl(file, mode);
cache.put(file, sp);
return sp;
}
}
if ((mode & Context.MODE_MULTI_PROCESS) != 0 ||
getApplicationInfo().targetSdkVersion < android.os.Build.VERSION_CODES.HONEYCOMB) {
// If somebody else (some other process) changed the prefs
// file behind our back, we reload it. This has been the
// historical (if undocumented) behavior.
sp.startReloadIfChangedUnexpectedly();
}
return sp;
}
getSharedPreferences()就是返回了File文件对应的SharedPreferenceImpl对象。
整个获取sharedPreferences的过程:首先建立文件名和File文件的一一对应关系,将数据存储在mSharedPrefsPaths中,如果mSharedPrefsPaths中有文件了,则直接使用不需要重复创建,根据File文件找到对应的SharedPreferenceImpl对象并返回。
SharedPreferencesImpl
SharedPreferencesImpl是SharedPreferences的子类,首先看一下SharedPreferences接口中的方法。
public interface SharedPreferences {
public interface OnSharedPreferenceChangeListener {
void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key);
}
public interface Editor {
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);
Editor clear();
boolean commit();
void apply();
}
Map<String, ?> getAll();
@Nullable
String getString(String key, @Nullable String defValue);
@Nullable
Set<String> getStringSet(String key, @Nullable Set<String>