SharedPreference源码解析
来源:互联网 发布:mac steam 目录 编辑:程序博客网 时间:2024/06/03 17:12
概要:
SharedPreference属于轻量级的键值存储方式,以xml文件保存。作为Android存储数据的
一个重要的方式,值得透彻分析一下。
SharedPreference的获取方式:
首先SharedPreference的获取方式,有两种Activity的getSharedPreference(int mode)与Context的
getSharedPreference(String name, int mode);
先看Activity的getSharedPreference(int mode):
public SharedPreferences getPreferences(@Context.PreferencesMode int mode) {//getLocalClassName 就是Activity的类名 return getSharedPreferences(getLocalClassName(), mode);}
@Overridepublic SharedPreferences getSharedPreferences(String name, int mode) { return mBase.getSharedPreferences(name, mode);//mBase是Context实例}
所以最后还是调用了Context.getSharedPreference(String name, int mode),但是Context是抽象类,
它的的实现是ContextImp(这涉及到Activity的启动过程,不在这里赘述了)。
现在我们来看一下ContextImp的getSharedPreference(String name, int mode)(为了方便展示我会去掉一些多余的代码)
@Overridepublic SharedPreferences getSharedPreferences(String name, int mode) { File file; synchronized (ContextImpl.class) { if (mSharedPrefsPaths == null) { mSharedPrefsPaths = new ArrayMap<>(); } file = mSharedPrefsPaths.get(name); if (file == null) { file = getSharedPreferencesPath(name);//创建file mSharedPrefsPaths.put(name, file); } } return getSharedPreferences(file, mode);//获取SharedPreference。 }这里会先根据name判断相应的File是否存在,如果不存在就利用getSharedPreferencesPath(name)创建一个新
的File,然后再回调getSharedPreferences(File file, int mode)。
其中创建File的函数:getSharedPreferencesPath(name):
@Override public File getSharedPreferencesPath(String name) { return makeFilename(getPreferencesDir(), name + ".xml");//getPreferencesDir父目录的确认 }
private File makeFilename(File base, String name) { if (name.indexOf(File.separatorChar) < 0) { return new File(base, name); } }其中getPreferencesDir的确认涉及到了PackageInfo的datadir,和process.myUid();
我们继续看getSharedPreference(File file,int mode);
@Override public SharedPreferences getSharedPreferences(File file, int mode) { checkMode(mode); 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; } } return sp; }
private ArrayMap<File, SharedPreferencesImpl> getSharedPreferencesCacheLocked() { if (sSharedPrefsCache == null) { sSharedPrefsCache = new ArrayMap<>(); } final String packageName = getPackageName(); ArrayMap<File, SharedPreferencesImpl> packagePrefs = sSharedPrefsCache.get(packageName); if (packagePrefs == null) { packagePrefs = new ArrayMap<>(); sSharedPrefsCache.put(packageName, packagePrefs); } return packagePrefs; }我们先拿到ArrayMap<File, SharedPreferencesImp>类型的map,再从map中检查,没有则重新创建
其中SharedPreferencesImp就是SharedPreference的实现类。
最后我们查看SharedPreferencesImp类:
final class SharedPreferencesImpl implements SharedPreferences { 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(); }}可以看到,SharedPreferencesImp的构造中,开启线程去加载文件xml的数据。
总结:SharedPreference获取的实例是一个单例,且在创建的时候开线程去解析加载文件数据。
SharedPreference.edit()获取Editor。
public Editor edit() { synchronized (mLock) { awaitLoadedLocked(); } return new EditorImpl(); }可以看到返回了一个Editor的实现类EditorImpl,但是前面有个方法awaitLoadedLocked()方法,采用的
是await和notify,处理并发,实现逻辑:loadFromDisk数据加载完成前,awaitLoadedLocked处于阻塞状态。
Editor.putxxxx方法,这里举例putString(String key, String value)
public Editor putString(String key, @Nullable String value) { synchronized (mLock) { mModified.put(key, value); return this; } }
很简单,就是将数据放到内存中。
Editor.commit()数据提交后写入磁盘。
public boolean commit() { MemoryCommitResult mcr = commitToMemory() SharedPreferencesImpl.this.enqueueDiskWrite( mcr, null /* sync write on this thread okay */); try { mcr.writtenToDiskLatch.await(); } catch (InterruptedException e) { return false; } finally { } notifyListeners(mcr); return mcr.writeToDiskResult; }真正重要的方法就两个commitToMemory将改变数据和原先的数据整理在一起(Map中,待写入数据),
封装到MemoryCommitResult,然后enqueueDiskWrite正式写到磁盘。
commitToMemory{ long memoryStateGeneration; List<String> keysModified = null; Set<OnSharedPreferenceChangeListener> listeners = null; Map<String, Object> mapToWriteToDisk; synchronized (SharedPreferencesImpl.this.mLock) { if (mDiskWritesInFlight > 0) { mMap = new HashMap<String, Object>(mMap); } mapToWriteToDisk = mMap; synchronized (mLock) {//整合数据 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); } } mModified.clear(); } }//封装到MemoryCommitResultzhong return new MemoryCommitResult(memoryStateGeneration, keysModified, listeners, mapToWriteToDisk); }enqueueDiskWrite:
private void enqueueDiskWrite(final MemoryCommitResult mcr, final Runnable postWriteRunnable) { final boolean isFromSyncCommit = (postWriteRunnable == null); final Runnable writeToDiskRunnable = new Runnable() { public void run() { synchronized (mWritingToDiskLock) { writeToFile(mcr, isFromSyncCommit); } synchronized (mLock) { mDiskWritesInFlight--; } if (postWriteRunnable != null) { postWriteRunnable.run(); } } }; if (isFromSyncCommit) { synchronized (mLock) { wasEmpty = mDiskWritesInFlight == 1; } if (wasEmpty) { writeToDiskRunnable.run();//关键点,说明是同步进行的,在主线调用,在主线执行。 return; } }
QueuedWork.queue(writeToDiskRunnable, !isFromSyncCommit);//apply(),则是放在任务队列中,异步执行 }
private void writeToFile(MemoryCommitResult mcr, boolean isFromSyncCommit) { try {此方法最重要的函数,调用XmlUtils写入操作。 XmlUtils.writeMapXml(mcr.mapToWriteToDisk, str); } catch (XmlPullParserException e) { Log.w(TAG, "writeToFile: Got exception:", e); } catch (IOException e) { Log.w(TAG, "writeToFile: Got exception:", e); } }
Eidtor.apply()
与Commit类似,只是它是异步的。在最后一步将任务放在任务队列中,多个任务线性一次执行。
又因为SharePreferenceImp单例原因,使用apply异步操作也是安全操作。推荐使用。
- SharedPreference源码解析
- SharedPreference解析
- Sharedpreference
- SharedPreference
- SharedPreference
- SharedPreference
- SharedPreference
- SharedPreference
- SharedPreference
- SharedPreference
- SharedPreference
- SharedPreference
- SharedPreference
- SharedPreference
- SharedPreference
- Android中的SharedPreference存储(附源码)
- Android SharedPreference 源码分析(一)
- SD卡,SharedPreference以及Pull解析
- redis cluster && Redis 作 mysql 的缓存服务器
- hdu 1270 小希的数表
- 10G数据量,只有2G内存,怎样找到中位数?
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- Android adb 命令无线调试andorid真机
- SharedPreference源码解析
- C++中的虚函数(表)实现机制以及用C语言对其进行的模拟实现
- 带你实现漂亮的滑动卷尺
- [ArcGIS] 空间分析(六) 追踪分析(台风路径)
- 数据结构 第10讲 好玩贪吃蛇——数字矩阵
- 嵌入式开发实践
- 谷歌浏览器跨域
- java类的初始化
- android定时器、消息任务与问题解决