SharedPreferences是一个轻量级的数据存储,并以key-value键值对的形式存在,符合xml文件存储
public interface SharedPreferences
具体实现
//SharedPreferences其实是一个接口而已
public interface SharedPreferences {
//定义一个用于在数据发生改变时调用的监听回调
public interface OnSharedPreferenceChangeListener {
//哪个key对应的值发生变化
void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key);
}
//编辑SharedPreferences对象设定值的接口
public interface Editor {
//一些编辑存储基本数据key-value的接口方法
Editor putString(String key, String value);
Editor putStringSet(String key, 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);
//删除指定key的键值对
Editor remove(String key);
//清空所有键值对
Editor clear();
//同步的提交到硬件磁盘
boolean commit();
//将修改数据原子提交到内存,而后异步提交到硬件磁盘
void apply();
}
//获取指定数据
Map<String, ?> getAll();
String getString(String key, String defValue);
Set<String> getStringSet(String key, Set<String> defValues);
int getInt(String key, int defValue);
long getLong(String key, long defValue);
float getFloat(String key, float defValue);
boolean getBoolean(String key, boolean defValue);
boolean contains(String key);
//针对preferences创建一个新的Editor对象,通过它你可以修改preferences里的数据,并且原子化的将这些数据提交回SharedPreferences对象
Editor edit();
//注册一个回调函数,当一个preference发生变化时调用
void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);
//注销一个之前(注册)的回调函数
void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);
}
public SharedPreferences getPreferences(int mode) {
return getSharedPreferences(getLocalClassName(), mode);
}
Activity的SharePreference实例获取方法只是对Context的getSharedPreferences再一次封装而已,使用getPreferences方法获取实例默认生成的xml文件名字是当前activity类名而已,此方法为Activity特有
public abstract SharedPreferences getSharedPreferences (String name, int mode)
getSharedPreferences("config", Context.MODE_PRIVATE);
/data/data/com.example.reboottest/shared_prefs
下生成了一个config.xml文件
获取SharedPreferences对象,其中第一参数为数据存储的文件名,并且会创建一个路径(data/packagename/shared_prefs/),第二个参数为Mode,具体有以下几种模式
模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件
多进程之间的使用
默认的为0,即MODE_PRIVATE
表示当前文件可以被其他应用读取
表示当前文件可以被其他应用写入
getSharedPreferences(context).edit()
在访问或修改数据之前需要先获取一个编辑器,通过 SharedPreferences.Editor方法
public abstract void onSharedPreferenceChanged (SharedPreferences sharedPreferences, String key)
当数据被增加,删除,修改后会调用此接口
在写操作commit时有三级锁操作,所以效率很低,所以当我们一次有多个修改写操作时等都批量put完了再一次提交确认,这样可以提高效率。
public boolean commit() {
//1.先通过commitToMemory方法提交到内存
MemoryCommitResult mcr = commitToMemory();
//2.写文件操作
SharedPreferencesImpl.this.enqueueDiskWrite(
mcr, null /* sync write on this thread okay */);
try {
//阻塞等待写操作完成,UI操作需要注意!!!所以如果不关心返回值可以考虑用apply替代。
mcr.writtenToDiskLatch.await();
} catch (InterruptedException e) {
return false;
}
//3.通知数据发生变化了
notifyListeners(mcr);
//4.返回写文件是否成功状态
return mcr.writeToDiskResult;
}
其实和commit类似,只不过他是异步写的,没在当前线程执行写文件操作,还有就是他不像commit一样返回文件是否写成功状态
public void apply() {
//有了上面commit分析,这个雷同,写数据到内存,返回数据结构
final MemoryCommitResult mcr = commitToMemory();
final Runnable awaitCommit = new Runnable() {
public void run() {
try {
//等待写文件结束
mcr.writtenToDiskLatch.await();
} catch (InterruptedException ignored) {
}
}
};
QueuedWork.add(awaitCommit);
//一个收尾的Runnable
Runnable postWriteRunnable = new Runnable() {
public void run() {
awaitCommit.run();
QueuedWork.remove(awaitCommit);
}
};
//这个上面commit已经分析过的,这里postWriteRunnable不为null,所以会在一个新的线程池调用postWriteRunnable的run方法
SharedPreferencesImpl.this.enqueueDiskWrite(mcr, postWriteRunnable);
// Okay to notify the listeners before it's hit disk
// because the listeners should always get the same
// SharedPreferences instance back, which has the
// changes reflected in memory.
//通知变化
notifyListeners(mcr);
}
return | method |
---|---|
abstract void | apply() |
abstract boolean | commit() |
1.apply没有返回值,而commit有返回值boolean,表示是否提交成功
2.apply提交失败后没有任何提示
3.在SharedPreferences的Editor中如果用commit()方法提交数据,其过程是先把数据更新到内存,然后在当前线程中写文件操作,提交完成返回提交状态;如果用的是apply()方法提交数据,首先也是写到内存,接着在一个新线程中异步写文件,然后没有返回值
通过edit()方法获取到haredPreferences.Editor编辑器
通过 putBoolean等方法添加数据,调用了Editor的putXXX后其实数据是没有存入SharePreference的,具体如下表
return | method |
---|---|
abstract SharedPreferences.Editor | clear() |
abstract SharedPreferences.Editor | putBoolean(String key, boolean value) |
abstract SharedPreferences.Editor | putFloat(String key, float value) |
abstract SharedPreferences.Editor | putInt(String key, int value) |
abstract SharedPreferences.Editor | putLong(String key, long value) |
abstract SharedPreferences.Editor | putString(String key, String value) |
abstract SharedPreferences.Editor | putStringSet(String key, Set values) |
abstract SharedPreferences.Editor | remove(String key) |
最后commit保存修改,将Editor的数据存入SharePreference文件
public Editor putBoolean(String key, boolean value) {
//同步锁操作
synchronized (this) {
//将我们要存储的数据放入mModified集合中
mModified.put(key, value);
//返回当前对象实例,方便这种模式的代码写法:putXXX().putXXX();
return this;
}
}
使用SharedPreferences对象来读取数据,一旦拿到SharePreference对象之后的getXXX操作其实都不再是文件读操作,如果读取到数据后,则获取,没有的话,读取默认的defValue默认值,具体代码如下:
return | method |
---|---|
abstract boolean | getBoolean(String key, boolean defValue) |
abstract float | getFloat(String key, float defValue) |
abstract int | getInt(String key, int defValue) |
abstract long | getLong(String key, long defValue) |
abstract String | getString(String key, String defValue) |
abstract Set | getStringSet(String key, Set defValues) |
public boolean getBoolean(String key, boolean defValue) {
//可以看见,和上面异步load数据使用的是同一个对象锁
synchronized (this) {
//阻塞等待异步加载线程加载完成notify
awaitLoadedLocked();
//加载完成后解析的xml数据放在mMap对象中,我们从mMap中找出指定key的数据
Boolean v = (Boolean)mMap.get(key);
//存在返回找到的值,不存在返回设置的defValue
return v != null ? v : defValue;
}
}
登录成功,保存对应的用户名及密码,登录不成功提示登录不成功,具体流程图如下:
MyPref.xml
at MyPref.xml <
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="user">admin</string>
<string name="pwd">123456</string>
</map>
项目演练代码:https://github.com/409144245/SharedPerfTest
参考链接