Android SharedPreferences实现原理
一.简介
在Android中,我们通常会需要存储一些数据,有一些大型的数据诸如图片、JSON数据等,可以通过读写File的方式实现;有一些大量级的关系型数据,可以通过数据库SQLite实现;还有一些简单的、无安全风险的键值对数据,可以通过Android提供的SharedPreferences实现。
SharedPreferences是一个轻量级的xml键值对文件,使用起来也是很方便。
//根据文件名,获取SharedPreferences对象;mode一般都使用MODE_PRIVATE,只能由该App访问
val sp = context.getSharedPreferences("setting", Context.MODE_PRIVATE)
//根据key,获取指定值
val needInitChannels = sp.getBoolean("isDebug", false)
//获取Editor编辑对象,用于编辑SharedPreferences
val editor = sp.edit()
editor.putBoolean("isDebug",true)
//同步提交到SharedPreferences文件,获取是否同步成功的结果
val res:Boolean = editor.commit()
//异步提交到SharedPreferences文件
editor.apply()
当我们第一次访问一个名为"setting"的SharedPreferences文件,系统会在应用数据目录下(/data/data/packageName/)的shared_prefs文件夹下,创建一个同名的xml文件。
二.实现原理
1.创建
我们是通过Context的getSharedPreferences()方法来获取一个SharedPreferences对象,而Context的实际逻辑载体,是在ContextImpl里,所以我们来看ContextImpl的该方法。
public SharedPreferences getSharedPreferences(String name, int mode) {
...
File file;
synchronized (ContextImpl.class) {
if (mSharedPrefsPaths == null) {
mSharedPrefsPaths = new ArrayMap<>();
}
//1.获取缓存File对象
file = mSharedPrefsPaths.get(name);
if (file == null) {
//生成File对象
file = getSharedPreferencesPath(name);
mSharedPrefsPaths.put(name, file);
}
}
//2.获取File对象对应的SharedPreferences对象
return getSharedPreferences(file, mode);
}
这里第一步我们可以看到,有一个ArrayMap会缓存每一个SharedPreferences文件对象,如果第一次加载的话,会调用getSharedPreferencesPath()生成File对象。
public File getSharedPreferencesPath(String name) {
return makeFilename(getPreferencesDir(), name + ".xml");
}
private File getPreferencesDir() {
synchronized (mSync) {
if (mPreferencesDir == null) {
///data/data/packageName/目录
mPreferencesDir = new File(getDataDir(), "shared_prefs");
}
return ensurePrivateDirExists(mPreferencesDir);
}
}
private static File ensurePrivateDirExists(File file, int mode, int gid, String xattr) {
if (!file.exists()) {
final String path = file.getAbsolutePath();
try {
Os.mkdir(path, mode);
...
}...
}
return file;
}
我们会看到,如果应用目录下还没有shared_prefs文件夹,则创建一个该文件夹。
public File getSharedPreferencesPath(String name) {
return makeFilename(getPreferencesDir(