目录
- 访问SharedPreferences
- SharedPreferences的创建与初始化
- Editor介绍
- 异步操作apply
- 同步操作commit
- 写入文件writeToFile
- QueuedWork介绍
- 系统组件中对于SharedPreferences的处理
- 总结
注:本文基于Android 8.1。
1. 访问SharedPreferences
SharedPreferences是Android系统提供的一种轻量级的数据存取方式,数据存取是通过键值对的形式,存放到xml中。
xml文件的存放路径为:/data/data/packageName/shared_prefs/
目录
在应用中可以调用context.getSharedPreferences(fileName, mode)使用获取到SharedPreferences,如果操作比较简单,或者希望异步操作,不需要等待结果,可以在存数据之后调用apply();
如果是批量操作,并且需要知道是否写入文件成功,则可以存数据之后,调用commit();
对Context有了解的都知道,context中的方法调用最终会调用到ContextImpl中实现,其中关于getSharedPreferences的public方法有以下几个:
// 传入文件以及打开文件的模式获取SharedPreferences
public SharedPreferences getSharedPreferences(File file, int mode)
// 传入文件名称以及打开文件的模式获取SharedPreferences
public SharedPreferences getSharedPreferences(String name, int mode)
// 根据文件名称获取相应的SharedPreferences对应的文件
public File getSharedPreferencesPath(String name)
看上去有三个方法,但是其实传递文件名称的方法在ContextImpl中也是调用传递文件的方法,所以就从getSharedPreferences(String name, int mode)
开始介绍。
方便起见,以下SharedPreferences简称为sp
。
2. SharedPreferences的创建与初始化
2.1 getSharedPreferences
public SharedPreferences getSharedPreferences(String name, int mode) {
...
File file;
synchronized (ContextImpl.class) {
// mSharedPrefsPaths是ContextImpl中的一个ArrayMap
// key是文件名,value是存放该文件名对应的sp的File对象
if (mSharedPrefsPaths == null) {
mSharedPrefsPaths = new ArrayMap<>();
}
//对于每一个创建的sp,如果不存在则创建对应的文件
file = mSharedPrefsPaths.get(name);
if (file == null) {
file = getSharedPreferencesPath(name);
mSharedPrefsPaths.put(name, file);
}
}
// 还是调用到了另外一个参数为File的重载方法
return getSharedPreferences(file, mode);
}
// 下面这两个方法可以看出,sp存放在App数据目录下的shared_prefs目录中
// 对应文件的名称就是在获取sp的时候传入的name,结尾添加一个 ".xml"
public File getSharedPreferencesPath(String name) {
return makeFilename(getPreferencesDir(), name + ".xml");
}
private File getPreferencesDir() {
synchronized (mSync) {
if (mPreferencesDir == null) {
mPreferencesDir = new File(getDataDir(), "shared_prefs");
}
return ensurePrivateDirExists(mPreferencesDir);
}
}
getSharedPreferences(file, mode)
public SharedPreferences getSharedPreferences(File file, int mode) {
// SharedPreferencesImpl类是核心,sp中数据的存取包括写入到文件都是由这个类来实现的
SharedPreferencesImpl sp;
synchronized (ContextImpl.class) {
// getSharedPreferencesCacheLocked去获取sp缓存,下面有对这个方法的介绍
// 这里获取到当前进程所有的存放的sp的map
// key是存放sp的File,value是这个sp对应的SharedPreferencesImpl对象
final ArrayMap<File, SharedPreferencesImpl> cache = getSharedPreferencesCacheLocked();
sp = cache.get(file);
if (sp == null) {
// 对传入的mode进行校验
// 在N以及之上的版本,不再支持MODE_WORLD_READABLE和MODE_WORLD_READABLE
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");
}
}
// 如果不存在则创建并存入map缓存中
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;
}
private ArrayMap<File, SharedPreferencesImpl> getSharedPreferencesCacheLocked() {
// sSharedPrefsCache是一个二级map
// 一集key是packageName,二级key是sp对应的File,value是sp对应的SharedPreferencesImpl对象
if (sSharedPrefsCache == null) {
sSharedPrefsCache = new ArrayMap<>();
}
final String packageName = getPackageName();
// 先以packageName为key,value是这个package对应的SharedPreferencesImpl的Map
// 如果不存在则创建map