源码分析:SharedPreferences实现
来源:互联网 发布:ios10软件不受信任 编辑:程序博客网 时间:2024/05/23 14:04
首先看Context.java可以看到:
public abstract SharedPreferences getSharedPreferences(String name, int mode);
由于Context.java只是一个接口。实际的Context为Application/Activity这些实现类。这些类都继承于 ContextWarpper,ContextWrapper可以看到:
@Override public SharedPreferences getSharedPreferences(String name, int mode) { return mBase.getSharedPreferences(name, mode); }
mBase为Context,其实现为ContextImpl,查看ContextImpl.java可以看到:
@Override public SharedPreferences getSharedPreferences(String name, int mode) { SharedPreferencesImpl sp; synchronized (ContextImpl.class) { if (sSharedPrefs == null) { sSharedPrefs = new ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>>(); } final String packageName = getPackageName(); ArrayMap<String, SharedPreferencesImpl> packagePrefs = sSharedPrefs.get(packageName); if (packagePrefs == null) { packagePrefs = new ArrayMap<String, SharedPreferencesImpl>(); sSharedPrefs.put(packageName, packagePrefs); } // 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"; } } sp = packagePrefs.get(name); if (sp == null) { File prefsFile = getSharedPrefsFile(name); sp = new SharedPreferencesImpl(prefsFile, mode); packagePrefs.put(name, 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. sp.startReloadIfChangedUnexpectedly(); } return sp; }
SharedPreferences的真正实现类为:SharedPreferencesImpl,本文主要分析SharedPreferencesImpl.java的实现。
SharedPreferencesImpl(File file, int mode) { mFile = file; mBackupFile = makeBackupFile(file); mMode = mode; mLoaded = false; mMap = null; startLoadFromDisk(); }
构造函数调用时,会调用startLoadFromDisk(),这个函数比较有意思:
private void startLoadFromDisk() { synchronized (this) { mLoaded = false; } new Thread("SharedPreferencesImpl-load") { public void run() { synchronized (SharedPreferencesImpl.this) { loadFromDiskLocked(); } } }.start(); } private void loadFromDiskLocked() { 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 { str = new BufferedInputStream( new FileInputStream(mFile), 16*1024); map = XmlUtils.readMapXml(str); } catch (XmlPullParserException e) { Log.w(TAG, "getSharedPreferences", e); } catch (FileNotFoundException e) { Log.w(TAG, "getSharedPreferences", e); } catch (IOException e) { Log.w(TAG, "getSharedPreferences", e); } finally { IoUtils.closeQuietly(str); } } } catch (ErrnoException e) { } mLoaded = true; if (map != null) { mMap = map; mStatTimestamp = stat.st_mtime; mStatSize = stat.st_size; } else { mMap = new HashMap<String, Object>(); } notifyAll(); }
startLoadFromDisk启动一个线程,线程调用loadFromDiskLocked(),这个方法首先检测.bak文件是否存在,如果存在就更名为非.bak结尾的文件。然后检测这个文件是否可读:如果可读,读取XML文件的键值对,并保存到Map中。读取完毕以后,调用notifyAll,看到这个,我们马上就会想到wait。看看wait在哪里?
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 { wait(); } catch (InterruptedException unused) { } } }
可以看到只要XML文件的数据没有加载完毕,就阻塞当前线程调用wait()。而这个awaitLoadedLocked()会在所有读取数据的地方都需要调用。
所以这意味着:SharedPreferencesImpl初始化的时候,会异步加载XML文件中保存的数据,然后读取数据的时候,会检查是否加载完毕,如果没有加载完毕,就挂起当前线程等待子线程加载完毕。想一想,如果保存的数据过多,XML文件很大,这个加载过程就会变长。如果在UI线程调用SharedPreferences,那么UI线程可能会阻塞一段时间。所以SharedPreferences如果保存的数据过多,对UI线程是有影响的。
- 源码分析:SharedPreferences实现
- SharedPreferences 源码分析
- Android SharedPreferences源码分析
- Android源码分析之SharedPreferences
- Android源码分析之SharedPreferences
- Android源码分析之SharedPreferences
- Android源码分析之SharedPreferences
- 源码分析多进程下的SharedPreferences
- Android面试题-SharedPreferences源码分析
- epoll源码实现分析
- epoll源码实现分析
- epoll源码实现分析
- Asynctask实现源码分析
- BadgeView实现源码分析
- Iterator实现源码分析
- Dubbo实现源码分析
- ViewPager实现源码分析
- Retrofit2实现源码分析
- Working with Linear Models
- linux命令之 tree 命令
- 集群
- HDU 3853 概率DP 解题报告
- ToLua学习笔记,通信(二)
- 源码分析:SharedPreferences实现
- String类与深浅拷贝
- 课堂学习——HDUOJ-1215
- 1007 Financial Management
- ACM 格式化输出,杨辉三角
- 提高.Net程序猿工作效率的开发工具
- 模板--二叉搜索树
- tomcat部署项目,不加项目名自动跳转
- poj 2096 概率DP 解题报告