Forver.微笑

面带微笑未必真的开心,但笑起的那一刻,心中的那些不开心的事已经不重要了~

0%

SharedPreferences使用常见问题

实际开发中,在持久化保存少量数据上,SharedPreference还是比较常用的。
本文不讲解SharedPreference的基本用法,主要讲解实际使用中可能出现的一些问题。

apply()和commit()的区别

apply()和commit()都是SharedPreference写入数据的方法。
commit()有返回值表示是否写数据成功,是同步写入,如果写入数据量过大,或造成线程阻塞。
apply()无返回值,是异步写入,推荐使用。

多进程不推荐使用SharedPreferences

虽然Context.getSharedPreferences()第2个参数是mode,当API Level>=11可选值有Mode.Context.MODE_MULTI_PROCESS支持多进程,但是API Level 23时已被标记为弃用,存在随时会不再支持的问题。
从源码看,SharedPreferences每次都从文件读写存在效率问题,使用缓存可以提高读写速度,但是不同进程的缓存可能存在不同步的问题。
目前SharedPreferences仍然支持Mode.Context.MODE_MULTI_PROCESS值,从源码看,每次获取SharedPreferences对象时会从磁盘重新读取最新文件内容。
然而考虑到Mode.Context.MODE_MULTI_PROCESS参数已被弃用,如果明确了数据需要在多个进程中使用,最好采用其他支持多进程的方式存取,比如Conprovider等。
github上有一个支持多进程的开源库MultiprocessSharedPreferences,查看源码可知,也是通过封装了ContentProvider来支持多进程的。

相关源码
在ContextImpl.java中

1
2
3
4
5
6
7
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();
}

SharedPrefercencesImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 void startReloadIfChangedUnexpectedly() {
synchronized (mLock) {
if (!hasFileChangedUnexpectedly()) {
return;
}
startLoadFromDisk();
}
}


private void startLoadFromDisk() {
synchronized (mLock) {
mLoaded = false;
}
new Thread("SharedPreferencesImpl-load") {
public void run() {
loadFromDisk();
}
}.start();
}

参考