android app深度优化—Shared Preference源码详解

前言

SharedPreferences是Android提供的数据持久化的一种手段,适合单进程、小批量的数据存储与访问。因为SharedPreferences的实现是基于单个xml文件实现的,并且,所有持久化数据都是一次性加载到内存,如果数据过大,是不合适采用SharedPreferences存放的。而适用的场景是单进程的原因同样如此,由于Android原生的文件访问并不支持多进程互斥,所以SharePreferences也不支持,如果多个进程更新同一个xml文件,就可能存在同不互斥问题。

SharedPreferences简单使用

创建

第一个参数是储存的xml文件名称,第二个是打开方式,一般就用Context.MODE_PRIVATE;

SharedPreferences sp=context.getSharedPreferences("名称", Context.MODE_PRIVATE);
复制代码

写入

//可以创建一个新的SharedPreference来对储存的文件进行操作
​
SharedPreferences sp=context.getSharedPreferences("名称", Context.MODE_PRIVATE);
​
//像SharedPreference中写入数据需要使用Editor
​
SharedPreference.Editor editor = sp.edit();
​
//类似键值对
​
editor.putString("name", "string");
​
editor.putInt("age", 0);
​
editor.putBoolean("read", true);
​
//editor.apply();
​
editor.commit();
复制代码
  • apply和commit都是提交保存,区别在于apply是异步执行的,不需要等待。不论删除,修改,增加都必须调用apply或者commit提交保存;
  • 关于更新:如果已经插入的key已经存在。那么将更新原来的key;
  • 应用程序一旦卸载,SharedPreference也会被删除;

读取

SharedPreference sp=context.getSharedPreferences("名称", Context.MODE_PRIVATE);
​
//第一个参数是键名,第二个是默认值
​
String name=sp.getString("name", "暂无");
​
int age=sp.getInt("age", 0);
​
boolean read=sp.getBoolean("isRead", false);
复制代码

4、检索

SharedPreferences sp=context.getSharedPreferences("名称", Context.MODE_PRIVATE);
​
//检查当前键是否存在
​
boolean isContains=sp.contains("key");
​
//使用getAll可以返回所有可用的键值
​
//Map<String,?> allMaps=sp.getAll();
复制代码

删除

当我们要清除SharedPreferences中的数据的时候一定要先clear()、再commit(),不能直接删除xml文件;

SharedPreference sp=getSharedPreferences("名称", Context.MODE_PRIVATE);
​
SharedPrefence.Editor editor=sp.edit();
​
editor.clear();
​
editor.commit();
复制代码
  • getSharedPreference() 不会生成文件,这个大家都知道;
  • 删除掉文件后,再次执行commit(),删除的文件会重生,重生文件的数据和删除之前的数据相同;
  • 删除掉文件后,程序在没有完全退出停止运行的情况下,Preferences对象所存储的内容是不变的,虽然文件没有了,但数据依然存在;程序完全退出停止之后,数据才会丢失;
  • 清除SharedPreferences数据一定要执行editor.clear(),editor.commit(),不能只是简单的删除文件,这也就是最后的结论,需要注意的地方

源码分析

获取SharedPreferences对象的过程

Context是一个抽象类,它的子类中有ContextImpl和ContextWrapper

Context mBase;
public SharedPreferences getSharedPreferences(String name, int mode) {
//这里其实调用的是ContextImpl的getSharedpreferences方法
       return mBase.getSharedPreferences(name, mode);
   }

最终还是要看看ContextImpl中的getSharedPreferences的具体实现:

public SharedPreferences getSharedPreferences(String name, int mode) {
        //当SDK< 19时,如果文件名为null则会初始化名字为"null"
        if (mPackageInfo.getApplicationInfo().targetSdkVersion <
                Build.VERSION_CODES.KITKAT) {
            if (name == null) {
                name = "null";
            }
        }
        File file;
        synchronized (ContextImpl.class) {
        //建立了文件名和File文件的一一对应关系
            if (mSharedPrefsPaths == null) {
                mSharedPrefsPaths = new ArrayMap<>();
            }
            file = mSharedPrefsPaths.get(name);
            if (file == null) {
            //在相应的sharedPreference下新建File,保存文件名为XXX.xml
                file = getSharedPreferencesPath(name);
                mSharedPrefsPaths.put(name, file);
            }
        }
        return getSharedPreferences(file, mode);
    }

新建File的缓存,使用Map建立了文件名和File文件的一一对应,如果没有文件则新建,并放入Map中,如果Map中有需要的文件,则直接使用get方法取出。最终调用了ContextImpl的getSharedPreferences方法。

 public SharedPreferences getSharedPreferences(File file, int mode) {
        SharedPreferencesImpl sp;
        synchronized (ContextImpl.class) {
        //在每个包下面建立了一个File-SharedPreferencesImpl对应关系的ArrayMap
        //getSharedPreferencesCacheLocked()根据包名返回相对应包下的ArrayMap
            final ArrayMap<File, SharedPreferencesImpl> cache = getSharedPreferencesCacheLocked();
            //从file-SharedPreferencesImpl键值对中根据当前file找到SharedPreferencesImpl实例
            sp = cache.get(file);
            //如果没有对应的SharedPreferencesImpl,就新建一个
            if (sp == null) {
            // 检查mode,如果是MODE_WORLD_WRITEABLE或者MODE_MULTI_PROCESS则直接抛异常
                checkMode(mode);
                if (getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.O) {
                    if (isCredentialProtectedStorage()
                            && !getSystemService(UserManager.class)
                                    .isUserUnlockingOrUnlocked(UserHandle.myUserId())) {
                        throw new Il
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值