日常开发中经常使用三分+彩平台开发 Q1157880099 源码地址:haozym.com存储数据,非常简单快捷,下面我们将对此进行分析
一、基本使用
封装工具类方便调用
class SpUtils{
private val context:Context=MyApplication.instance()
private val sp:SharedPreferences=context.getSharedPreferences(KEY_SP,Context.MODE_PRIVATE)
fun putString(key:String,value:String){
sp.edit().putString(key,value).commit()
}
fun getString(key:String):String{
return sp.getString(key,"")
}
companion object {
fun getInstance():SpUtils{
return SpUtils()
}
const val KEY_SP:String="sharedPreferenceKey"
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
存储数据
SpUtils.getInstance().putString("onClick","onClick")
1
读取数据
val str=SpUtils.getInstance().getString("onClick")
Log.e("peter","sp获取的数据为-> $str")
1
2
打印结果
E/peter: sp获取的数据为-> onClick
1
可存储数据类型及方法
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);
1
2
3
4
5
6
7
8
9
10
11
12
读取数据类型及方法
Map<String, ?> getAll();
String getString(String key, @Nullable String defValue);
Set<String> getStringSet(String key, @Nullable 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);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
清除sp数据方法
Editor clear();
1
二、缓存机制
getSharedPreferences ContextImpl中实现
@Override
public SharedPreferences getSharedPreferences(String name, int mode) {
// At least one application in the world actually passes in a null
// name. This happened to work because when we generated the file name
// we would stringify it to "null.xml". Nice.
if (mPackageInfo.getApplicationInfo().targetSdkVersion <
Build.VERSION_CODES.KITKAT) {
if (name == null) {
name = "null";
}
}
File file;
// 同步锁
synchronized (ContextImpl.class) {
if (mSharedPrefsPaths == null) {
mSharedPrefsPaths = new ArrayMap<>();
}
// 获取存储数据文件 存储路径 /data/data/包名/shared_prefs/sharedPreferenceKey.xml
file = mSharedPrefsPaths.get(name);
if (file == null) {
file = getSharedPreferencesPath(name);
mSharedPrefsPaths.put(name, file);
}
}
return getSharedPreferences(file, mode);
}
@Override
public SharedPreferences getSharedPreferences(File file, int mode) {
checkMode(mode);
if (getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.O) {
if (isCredentialProtectedStorage()
&& !getSystemService(StorageManager.class).isUserKeyUnlocked(
UserHandle.myUserId())
&& !isBuggy()) {
throw new IllegalStateException("SharedPreferences in credential encrypted "
+ "storage are not available until after user is unlocked");
}
}
SharedPreferencesImpl sp;
synchronized (ContextImpl.class) {
final ArrayMap<File, SharedPreferencesImpl> cache = getSharedPreferencesCacheLocked();
sp = cache.get(file);
// 缓存数据
if (sp == null) {
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.
// 返回时其他进程在之后修改了prefs,重新加载一边该数据
sp.startReloadIfChangedUnexpectedly();
}
return sp;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
SharedPreferencesImpl(file, mode)
SharedPreferencesImpl(File file, int mode) {
mFile = file;
mBackupFile = makeBackupFile(file);
mMode = mode;
mLoaded = false;
mMap = null;
// 从磁盘加载数据
startLoadFromDisk();
}
private void startLoadFromDisk() {
// 同步锁
synchronized (mLock) {
mLoaded = false;
}
// 开启子线程从磁盘加载数据
new Thread("SharedPreferencesImpl-load") {
public void run() {
loadFromDisk();
}
}.start();
}
private void loadFromDisk() {
synchronized (mLock) {
if (mLoaded) {
return;
}
// 如果备份的文件存在
if (mBackupFile.exists()) {
// 删除文件
mFile.delete();
// 文件重命名
mBackupFile.renameTo(mFile);
}
}
// Debugging
if (mFile.exists() && !mFile.canRead()) {
Log.w(TAG, "Attempt to read preferences file " + mFile + " without permission");
}
Map map = null;
StructStat stat = null;
try {
stat = Os.stat(mFile.getPath());
if (mFile.canRead()) {
BufferedInputStream str = null;
try {
// 读取xml文件数据
str = new BufferedInputStream(
new FileInputStream(mFile), 16*1024);// 数据缓冲区为16M 将数据暂时存储到数据缓冲区
map = XmlUtils.readMapXml(str);
} catch (Exception e) {
Log.w(TAG, "Cannot read " + mFile.getAbsolutePath(), e);
} finally {
IoUtils.closeQuietly(str);
}
}
} catch (ErrnoException e) {
/* ignore */
}
synchronized (mLock) {
mLoaded = true;
if (map != null) {
mMap = map;
mStatTimestamp = stat.st_mtime;
mStatSize = stat.st_size;
} else {
mMap = new HashMap<>();
}
// 唤醒锁
mLock.notifyAll();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
了解了创建sharepreference对象接下来看使用该对象存储数据
编辑数据我们使用Editor实现,而Editor是一个接口,具体实现交给其实现类
EditorImpl
public final class EditorImpl implements Editor {
private final Object mLock = new Object();
@GuardedBy("mLock")
private final Map<String, Object> mModified = Maps.newHashMap();
@GuardedBy("mLock")
private boolean mClear = false;
public Editor putString(String key, @Nullable String value) {
synchronized (mLock) {
// 将数据存储到hashMap中
mModified.put(key, value);
return this;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
commit 将数据写入磁盘,并返回是否写入成功布尔值
public boolean commit() {
long startTime = 0;
if (DEBUG) {
startTime = System.currentTimeMillis();
}
// 内存缓存结果
MemoryCommitResult mcr = commitToMemory();
// 将内存缓存数据结果添加到队列中
SharedPreferencesImpl.this.enqueueDiskWrite(
mcr, null /* sync write on this thread okay */);
try {
// 等待写入磁盘
mcr.writtenToDiskLatch.await();
} catch (InterruptedException e) {
return false;
} finally {
if (DEBUG) {
Log.d(TAG, mFile.getName() + ":" + mcr.memoryStateGeneration
+ " committed after " + (System.currentTimeMillis() - startTime)
+ " ms");
}
}
// 回调数据监听
notifyListeners(mcr);
// 将写入磁盘结果成功与否进行返回
return mcr.writeToDiskResult;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
继续查看commitToMemory() 将数据提交到内存中
// Returns true if any changes were made
private MemoryCommitResult commitToMemory() {
long memoryStateGeneration;
List<String> keysModified = null;
Set<OnSharedPreferenceChangeListener> listeners = null;
Map<String, Object> mapToWriteToDisk;
synchronized (SharedPreferencesImpl.this.mLock) {
// We optimistically don't make a deep copy until
// a memory commit comes in when we're already
// writing to disk.
if (mDiskWritesInFlight > 0) {
// We can't modify our mMap as a currently
// in-flight write owns it. Clone it before
// modifying it.
// noinspection unchecked
mMap = new HashMap<String, Object>(mMap);
}
mapToWriteToDisk = mMap;
mDiskWritesInFlight++;
boolean hasListeners = mListeners.size() > 0;
if (hasListeners) {
keysModified = new ArrayList<String>();
listeners = new HashSet<OnSharedPreferenceChangeListener>(mListeners.keySet());
}
synchronized (mLock) {
boolean changesMade = false;
if (mClear) {
if (!mMap.isEmpty()) {
changesMade = true;
mMap.clear();
}
mClear = false;
}
for (Map.Entry<String, Object> e : mModified.entrySet()) {
String k = e.getKey();
Object v = e.getValue();
// "this" is the magic value for a removal mutation. In addition,
// setting a value to "null" for a given key is specified to be
// equivalent to calling remove on that key.
// 值为空移除对应的键
if (v == this || v == null) {
if (!mMap.containsKey(k)) {
continue;
}
mMap.remove(k);
} else {
if (mMap.containsKey(k)) {
Object existingValue = mMap.get(k);
if (existingValue != null && existingValue.equals(v)) {
continue;
}
}
// 存储数据
mMap.put(k, v);
}
changesMade = true;
if (hasListeners) {
keysModified.add(k);
}
}
mModified.clear();
if (changesMade) {
mCurrentMemoryStateGeneration++;
}
memoryStateGeneration = mCurrentMemoryStateGeneration;
}
}
return new MemoryCommitResult(memoryStateGeneration, keysModified, listeners,
mapToWriteToDisk);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
notifyListeners(mcr) 通知监听
private void notifyListeners(final MemoryCommitResult mcr) {
if (mcr.listeners == null || mcr.keysModified == null ||
mcr.keysModified.size() == 0) {
return;
}
if (Looper.myLooper() == Looper.getMainLooper()) {
for (int i = mcr.keysModified.size() - 1; i >= 0; i--) {
final String key = mcr.keysModified.get(i);
for (OnSharedPreferenceChangeListener listener : mcr.listeners) {
if (listener != null) {
// 通过回调将内存提交结果传给sp监听
listener.onSharedPreferenceChanged(SharedPreferencesImpl.this, key);
}
}
}
} else {
// Run this function on the main thread.
ActivityThread.sMainThreadHandler.post(new Runnable() {
public void run() {
notifyListeners(mcr);
}
});
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apply
public void apply() {
final long startTime = System.currentTimeMillis();
// 获取提交到内存中的数据
final MemoryCommitResult mcr = commitToMemory();
final Runnable awaitCommit = new Runnable() {
public void run() {
try {
// 直接添加到写入磁盘等待
mcr.writtenToDiskLatch.await();
} catch (InterruptedException ignored) {
}
if (DEBUG && mcr.wasWritten) {
Log.d(TAG, mFile.getName() + ":" + mcr.memoryStateGeneration
+ " applied after " + (System.currentTimeMillis() - startTime)
+ " ms");
}
}
};
QueuedWork.addFinisher(awaitCommit);
Runnable postWriteRunnable = new Runnable() {
public void run() {
awaitCommit.run();
QueuedWork.removeFinisher(awaitCommit);
}
};
// 开启子线程写入到磁盘
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);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
相较于commit方法,apply无返回值,直接开启子线程进行数据写入磁盘操作,线程不安全,但是相较于commit单线程写入效率会比较高
读取数据
@Nullable
public String getString(String key, @Nullable String defValue) {
synchronized (mLock) {
awaitLoadedLocked();
// 通过map键获取值
String v = (String)mMap.get(key);
// 如果值为空显示设置的默认值
return v != null ? v : defValue;
}
}
1
2
3
4
5
6
7
8
9
10
awaitLoadedLocked(); 等待锁,防止多线程问题造成数据错误
private void awaitLoadedLocked() {
if (!mLoaded) {
// Raise an explicit StrictMode onReadFromDisk for this
// thread, since the real read will be in a different
// thread and otherwise ignored by StrictMode.
BlockGuard.getThreadPolicy().onReadFromDisk();
}
while (!mLoaded) {
try {
mLock.wait();
} catch (InterruptedException unused) {
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
总结:
1、sharedPreferences可以存储多种数据类型
2、存储位置位于/data/data/包名/shared_prefs/sharedPreferenceKey.xml
3、sharedPreferences通过xml文件存储数据,获取的时候在通过解析xml文件获取
4、apply方法是异步处理,无返回值;commit方法是同步处理,返回布尔值
作者:VipPeterGee
来源:CSDN
原文:https://blog.csdn.net/sinat_35241409/article/details/88248819
版权声明:本文为博主原创文章,转载请附上博文链接!