原理
创建
- 创建sp文件的File对象
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16class ContextImpl { SharedPreferences getSP(String name, int mode) { ... synchronzed (ContextImpl.class) { ... file = mSharedPrefsPaths.get(name); if (file == null) { file = getSHaredPreferencesPath(name); //就是计算出默认sp文件的路径,用这个路径创建File mSharedPrefsPaths.put(name, file); } } // 获取sp return getSharedPreferences(file, mode); } }
- 创建sp对象
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class ContextImpl { SP getSP(File file, int mode) { . synchronized (ComtextImpl.class) { .. if (sp == null) { ... sp = new SPImpl(file, mode); // 创建的地方 cache.put(file, sp); // 有缓存的,上面省略了 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
33class SPImpl { SPImpl(File file, int mode) { ... startLoadFromDisk(); // 新建线程,执行load操作 } void loadFromDisk() { ... try { if (mFile.canRead()) { . try { str = new BufferedInputStream( new FileInputStream(mFile), 16*1026 ); // SP的文件 map = (Map<String, Object>) XmlUtils.readMapXml(str); // 对 XmlPullParser 的封装,解析sp文件到内存里 } } } synchronized (mLock) { .. try { if () { if (map != null) { mMap = map; // 保存到成员变量 ... } } } } } }
修改
获取EditorImpl 来执行修改操作
获取方法是 SPImpl.edit()
复制代码
1
2
3
4
5
6
7class SPImpl { Editor edit() { . return new EditorImpl(); } }
保存
1. 先把要保存的数据,保存到mModified 里
复制代码
1
2
3
4
5
6
7
8
9
10
11class SPImpl { class EditorImpl { Editor putString(String key, String value) { synchronized (mEditorLock) { mModified.put(key, value); return this; } } } }
2. 调用apply() 或者 commit() 方法,把修改写入文件里
apply() 方法
- toMemeory:就是把数据同步到内存里。在 commitToMemory() 方法里,已经把修改的数据 EditorImpl.mModified 同步到 SPImpl.mMap 里了
- disk: 就是把数据写到文件里。调用 enqueueDiskWrite() 同步到disk 里
写到memory
复制代码
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
51class SPImpl { class EditorImpl { void apply() { . // 把要修改的数据,更新到mMap里,并用mMap生成 这个result MemoryCommitResult mcr = commitToMemory(); Runnable awaitCommit = new Runnable() { void run() { mcr.writtenToDiskLatch.await(); // 是一个CountDownLatch,本质就是LockSupport.park() } }; . // 这个Runnable 就是执行 CountDownLatch.await()。让线程park() Runnable postWriteRunnable = new Runnable() { void run() { awaitCommit.run(); . } } // 主要是这个函数 SPImpl.this.enqueueDiskWrite(mcr, postWriteRunnable); . // 分发listener的监听,不管 } // 要修改的数据保存在mModified 里 // 文件里的数据保存在mMap 里 // 用 mModified 数据去修改 mMap里的数据,这样mMap就是修改后的数据了 MemoryCommitResult commitToMemory() { ... synchronized (SPImpl.this.class) { ... mapToWriteToDisk = mMap; ... synchronized (mEditorLock) { ... for (Map.Entry<String, Object> e : mModified.entrySet()) { .. if (v == this || v == null) { // 删除 .. mapToWriteToDisk.remove(k); // mapToWriteToDisk 是从文件读取出来的数据。这里是删除 } else { ... // 如果有相同的数据,则continue mapToWriteToDisk.put(k, v); } } } } return new MemoryCommitResult(..., mapToWriteToDisk); } } }
写到disk
- “queued-work-looper” 线程中 把修改写入disk,并且执行countDown()
- 写入disk 完成后,执行await(),因为已经执行countDown()了,所以没有park线程
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21class SPImpl { void enqueueDiskWrite(MemoryCommitResult mcr, Runnable postWriteRunnable) { . Runnable writeToDiskRunnable = new Runnable() { void run() { synchronized(mWriteToDiskLock) { // 写入disk writeToFile(mcr, isSync); } ... if (postWriteRunnable != null) { postWriteRunnable.run(); // 执行 线程的park() } } } ... // 放到名叫 "queued-work-looper" 的线程里运行writeToDiskRunnable QueueWork.queue(writeToDiskRunnable, !isSync); } }
commit() 方法
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14class SPImpl { class EditorImpl { boolean commit() { ... // 把修改同步到SPImpl.mMap 中,SPImpl.mMap 也保存到 mcr里 MemoryCommitResult mcr = commitToMemory(); // 在调用commit的线程里,执行写入disk的操作。 SPImpl.this.enqueueDiskWrite(mcr, null); // 写入disk结束时,会设置 mcr.writeToDiskResult 是否写入成功 return mcr.writeToDiskResult; } } }
最后
以上就是超帅树叶最近收集整理的关于SharedPreference原理的全部内容,更多相关SharedPreference原理内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复