美文网首页
Android SharedPreference源码阅读

Android SharedPreference源码阅读

作者: 普通的程序员 | 来源:发表于2018-10-09 17:21 被阅读0次

    SharedPreferences是一个interface
    Editor是SP的内部interface

    真正的实现类是SharedPreferencesImpl类和EditorImpl类
    在ContextImpl类里可以看到其真实调用

    @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.
                sp.startReloadIfChangedUnexpectedly();
            }
            return sp;
        }
    

    其构造方法SharedPreferencesImpl(file, mode)
    内部调用startLoadFromDisk();
    该方法再开启线程进行loadFromDisk();
    源码阅读参考
    https://www.jianshu.com/p/31ffd0498496

    在SP解析xml时,会遇到null kv的问题
    https://www.jianshu.com/p/796ba810aa46
    根源在于4.X的sdk里允许了往SharedPreferences里写入key为null的值而不允许取出来,并且在之前没有从磁盘中读取到值到内存中,在对值进行copy的时候就"丢失",从而导致写入进去的新文件里没有以前的旧值,由此现象上来看好像是某些值被删除了,但实际上确切的说应该是被空值所覆盖。

    滥用SP可能造成的问题
    http://weishu.me/2016/10/13/sharedpreference-advices/?hmsr=toutiao.io

    大SP文件的读取:
    1.第一次从sp中获取值的时候,有可能阻塞主线程,使界面卡顿、掉帧;
    2.解析sp的时候会产生大量的临时对象,导致频繁GC,引起界面卡顿;
    3.这些key和value会永远存在于内存之中,占用大量内存。

    卡顿是因为下面这个方法,每一个getXX,都会一直在wait,
    在load没有结束前,mLoaded会一直是false

    private void awaitLoadedLocked() {
        while (!mLoaded) {
            try {
                wait();
            } catch (InterruptedException unused) {
            }
        }
    }
    

    【SharedPreferences.Editor 有 apply 和 commit 两个方法用于提交数据编辑,这两个方法的区别在于:

    apply没有返回值而commit返回boolean表明修改是否提交成功

    apply是将修改数据原子提交到内存, 而后异步真正提交到硬件磁盘, 而commit是同步的提交到硬件磁盘,因此,在多个并发的提交commit的时候,他们会等待正在处理的commit保存到磁盘后在操作,从而降低了效率。而apply只是原子的提交到内容,后面有调用apply的函数的将会直接覆盖前面的内存数据,这样从一定程度上提高了很多效率。

    apply方法不会提示任何失败的提示。

    由于在一个进程中,sharedPreference是单实例,一般不会出现并发冲突,如果对提交的结果不关心的话,建议使用apply,当然需要确保提交成功且有后续操作的话,还是需要用commit的。】
    --来源https://www.jianshu.com/p/13f26d68b02e

    整个apply分为三个步骤:

    • 通过commitToMemory写入到内存中
    • 通过enqueueDiskWrite写入到磁盘中
    • 通知监听者

    第二步的写操作SharedPreferencesImpl.this.enqueueDiskWrite(mcr, postWriteRunnable)的内部实现稍有不同。
    API 25:
    QueuedWork.singleThreadExecutor().execute(writeToDiskRunnable);
    为核心线程只有一个线程的线程池;
    API 26:
    QueuedWork.queue(writeToDiskRunnable, !isFromSyncCommit);
    为handler

    跨进程的支持
    在构造函数就可以看到,实际上就是重新读取一次xml文件,所以对于多进程的支持并不是很好。
    Google建议使用contentProvider
    https://www.jianshu.com/p/875d13458538

    SharedPreferences 线程阻塞及吃内存原因面试题
    https://mp.weixin.qq.com/s/VRUXQvmEEveNVR-DQD5w9Q

    坑点分析
    主要是一个flag值
    https://www.jianshu.com/p/40e42da910e2

    https://www.jianshu.com/p/c4fa942d8153

    相关文章

      网友评论

          本文标题:Android SharedPreference源码阅读

          本文链接:https://www.haomeiwen.com/subject/hwkyaftx.html