Android SharedPreferences原理分析

本文深入探讨了Android的SharedPreferences,从访问、创建初始化到Editor的使用,详细解析了apply的异步操作和commit的同步操作,以及涉及的QueuedWork机制。文章强调了在主线程中避免频繁操作SharedPreferences以防止卡顿甚至ANR的问题,并提供了使用建议。
摘要由CSDN通过智能技术生成

目录

  • 访问SharedPreferences
  • SharedPreferences的创建与初始化
  • Editor介绍
  • 异步操作apply
  • 同步操作commit
  • 写入文件writeToFile
  • QueuedWork介绍
  • 系统组件中对于SharedPreferences的处理
  • 总结

注:本文基于Android 8.1。

1. 访问SharedPreferences

SharedPreferences是Android系统提供的一种轻量级的数据存取方式,数据存取是通过键值对的形式,存放到xml中。
xml文件的存放路径为:/data/data/packageName/shared_prefs/目录
在应用中可以调用context.getSharedPreferences(fileName, mode)使用获取到SharedPreferences,如果操作比较简单,或者希望异步操作,不需要等待结果,可以在存数据之后调用apply();
如果是批量操作,并且需要知道是否写入文件成功,则可以存数据之后,调用commit();
对Context有了解的都知道,context中的方法调用最终会调用到ContextImpl中实现,其中关于getSharedPreferences的public方法有以下几个:

// 传入文件以及打开文件的模式获取SharedPreferences
public SharedPreferences getSharedPreferences(File file, int mode)
// 传入文件名称以及打开文件的模式获取SharedPreferences
public SharedPreferences getSharedPreferences(String name, int mode)
// 根据文件名称获取相应的SharedPreferences对应的文件
public File getSharedPreferencesPath(String name)

看上去有三个方法,但是其实传递文件名称的方法在ContextImpl中也是调用传递文件的方法,所以就从getSharedPreferences(String name, int mode)开始介绍。
方便起见,以下SharedPreferences简称为sp

2. SharedPreferences的创建与初始化

2.1 getSharedPreferences

    public SharedPreferences getSharedPreferences(String name, int mode) {
        ...

        File file;
        synchronized (ContextImpl.class) {
            // mSharedPrefsPaths是ContextImpl中的一个ArrayMap
            // key是文件名,value是存放该文件名对应的sp的File对象
            if (mSharedPrefsPaths == null) {
                mSharedPrefsPaths = new ArrayMap<>();
            }
            //对于每一个创建的sp,如果不存在则创建对应的文件
            file = mSharedPrefsPaths.get(name);
            if (file == null) {
                file = getSharedPreferencesPath(name);
                mSharedPrefsPaths.put(name, file);
            }
        }
        // 还是调用到了另外一个参数为File的重载方法
        return getSharedPreferences(file, mode);
    }

    // 下面这两个方法可以看出,sp存放在App数据目录下的shared_prefs目录中
    // 对应文件的名称就是在获取sp的时候传入的name,结尾添加一个 ".xml"
    public File getSharedPreferencesPath(String name) {
        return makeFilename(getPreferencesDir(), name + ".xml");
    }

    private File getPreferencesDir() {
        synchronized (mSync) {
            if (mPreferencesDir == null) {
                mPreferencesDir = new File(getDataDir(), "shared_prefs");
            }
            return ensurePrivateDirExists(mPreferencesDir);
        }
    }

getSharedPreferences(file, mode)

    public SharedPreferences getSharedPreferences(File file, int mode) {
        // SharedPreferencesImpl类是核心,sp中数据的存取包括写入到文件都是由这个类来实现的
        SharedPreferencesImpl sp;
        synchronized (ContextImpl.class) {
            // getSharedPreferencesCacheLocked去获取sp缓存,下面有对这个方法的介绍
            // 这里获取到当前进程所有的存放的sp的map
            // key是存放sp的File,value是这个sp对应的SharedPreferencesImpl对象
            final ArrayMap<File, SharedPreferencesImpl> cache = getSharedPreferencesCacheLocked();
            sp = cache.get(file);
            if (sp == null) {
                // 对传入的mode进行校验
                // 在N以及之上的版本,不再支持MODE_WORLD_READABLE和MODE_WORLD_READABLE
                checkMode(mode);
                if (getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.O) {
                    if (isCredentialProtectedStorage()
                            && !getSystemService(UserManager.class)
                                    .isUserUnlockingOrUnlocked(UserHandle.myUserId())) {
                        throw new IllegalStateException("SharedPreferences in credential encrypted "
                                + "storage are not available until after user is unlocked");
                    }
                }
                // 如果不存在则创建并存入map缓存中
                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;
    }

    private ArrayMap<File, SharedPreferencesImpl> getSharedPreferencesCacheLocked() {
        // sSharedPrefsCache是一个二级map
        // 一集key是packageName,二级key是sp对应的File,value是sp对应的SharedPreferencesImpl对象
        if (sSharedPrefsCache == null) {
            sSharedPrefsCache = new ArrayMap<>();
        }

        final String packageName = getPackageName();
        // 先以packageName为key,value是这个package对应的SharedPreferencesImpl的Map
        // 如果不存在则创建map
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值