Open kukyxs opened 4 years ago
//getSharedPreferences 获取 SP 的核心源码 class ContextImpl extends Context { //Context会把对应 SP 缓存起来 private static ArrayMap<String, ArrayMap<File, SharedPreferencesImpl>> sSharedPrefsCache; ...... @Override public SharedPreferences getSharedPreferences(File file, int mode) { ...... SharedPreferencesImpl sp; synchronized (ContextImpl.class) { final ArrayMap<File, SharedPreferencesImpl> cache = getSharedPreferencesCacheLocked(); sp = cache.get(file); if (sp == null) { //第一次或者新进程中时缓存没有就新 new 一个对应实例 sp = new SharedPreferencesImpl(file, mode); cache.put(file, sp); return sp; } } ...... return sp; } ...... }
接着看看 SharedPreferencesImpl 实例化及通过 SharedPreferences 获取一个指定 key 的值的核心源码部分
//一个File对应的一个SP实例 final class SharedPreferencesImpl implements SharedPreferences { //用来存储该SP的所有Key-Value对 private Map<String, Object> mMap; SharedPreferencesImpl(File file, int mode) { ...... //构造方法从磁盘加载SP文件 startLoadFromDisk(); } private void startLoadFromDisk() { ...... //启动一个名字为SharedPreferencesImpl-load的线程从磁盘读文件 new Thread("SharedPreferencesImpl-load") { public void run() { loadFromDisk(); } }.start(); } //子线程中读取文件解析成key-value对Map private void loadFromDisk() { ...... 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 (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<>(); } //子线程读取SP文件到mMap成功后通过notify通知释放阻塞锁 mLock.notifyAll(); } } //通过SharedPreferences对象获取指定key的值 //(一般与SharedPreferences获取在一个线程,主线程) public int getInt(String key, int defValue) { synchronized (mLock) { //阻塞等待SP读取到内存后再get awaitLoadedLocked(); Integer v = (Integer)mMap.get(key); return v != null ? v : defValue; } } private void awaitLoadedLocked() { ...... while (!mLoaded) { try { //阻塞等待SP读取到内存完成 mLock.wait(); } catch (InterruptedException unused) { } } } ...... }
所以说 SharedPreferences 读取 Map 虽然在子线程,但是其 getX(key) 系列方法想要调用的前提是 SharedPreferences 子线程已经读取完成,否则就会阻塞,所以 SharedPreferences 中如果存储太大内容或者太多内容导致 XML 解析等变慢就会导致后面的 getX(key) 阻塞主线程,从而导致主线程卡顿,所以说 SharedPreferences 是轻量级的持久化工具。
接着看看 SharedPreferencesImpl 实例化及通过 SharedPreferences 获取一个指定 key 的值的核心源码部分
所以说 SharedPreferences 读取 Map 虽然在子线程,但是其 getX(key) 系列方法想要调用的前提是 SharedPreferences 子线程已经读取完成,否则就会阻塞,所以 SharedPreferences 中如果存储太大内容或者太多内容导致 XML 解析等变慢就会导致后面的 getX(key) 阻塞主线程,从而导致主线程卡顿,所以说 SharedPreferences 是轻量级的持久化工具。