Sharepreferences 使用和实现分析

是什么

Android平台用于存储轻量级数据的存储方式,以键值对(key-value)的方式来进行存储,本质上是一个xml 文件。

怎么用

1、通过Context,获取SharedPreferences对象;
2、创建SharedPreferences.Editor对象;
3、写入数据并执行commit操作;

Context context;
SharedPreferences sharedPreferences = context.getSharedPreferences("sptest",MODE_PRIVATE);
        SharedPreferences.Editor editor=sharedPreferences.edit();
        editor.putString("name","名字");
        editor.commit();

执行上面的操作之后,就会在 data/data/你的应用名称/shared_prefs 文件夹下创建 sptest.xml 文件,并写入对应的数据。
getSharedPreferences传入的参数,为 MODE_PRIVATE,也就是默认的模式。Android支持的模式一共有以下四种操作模式。四种操作模式分别为:

1. MODE_APPEND: 追加方式存储
2. MODE_PRIVATE: 私有方式存储,其他应用无法访问
3. MODE_WORLD_READABLE: 表示当前文件可以被其他应用读取
4. MODE_WORLD_WRITEABLE: 表示当前文件可以被其他应用写入

现在只推荐使用MODE_PRIVATE这种模式,其他的几种模式,已经被官方弃用了,不再推荐使用。甚至在N版本以上,会直接抛异常。
在这里插入图片描述

1、通过上面获取到的SharedPreferences,执行器getString 方法即可;

String name = sharedPreferences.getString("name", "默认值");

实现原理

SharedPreferences是一个接口,对应的实现者是,SharedPreferencesImpl。在我们创建SharedPreferences的时候,需要传入对应的文件名称,然后将对应文件的数据读取到内存中,这个操作是异步的,在其内部新创建了一条名称为SharedPreferencesImpl-load的Thread进行读取的操作,

    private void startLoadFromDisk() {
        synchronized (this) {
            mLoaded = false;
        }
        new Thread("SharedPreferencesImpl-load") {
            public void run() {
                synchronized (SharedPreferencesImpl.this) {
                    loadFromDiskLocked();
                }
            }
        }.start();
    }    

当我们进行数据新增的时候,并不会立即进行数据落地,会将所有的操作,都先放进内存里面的Map,

        private final Map<String, Object> mModified = Maps.newHashMap();
        public Editor putString(String key, String value) {
            synchronized (this) {
                mModified.put(key, value);
                return this;
            }
        }

当需要进行数据落地的时候,需要调用commit或者apply方法。

        public void apply() {
        ...
            final Runnable awaitCommit = new Runnable() {
                    public void run() {
                        try {
                            mcr.writtenToDiskLatch.await();
                        } catch (InterruptedException ignored) {
                        }
                    }
                };
            Runnable postWriteRunnable = new Runnable() {
                    public void run() {
                        awaitCommit.run();
                        QueuedWork.remove(awaitCommit);
                    }
                };
            SharedPreferencesImpl.this.enqueueDiskWrite(mcr, postWriteRunnable);
        }

    private void writeToFile(MemoryCommitResult mcr) {
        if (mFile.exists()) {
            if (!mcr.changesMade) {
                mcr.setDiskWriteResult(true);
                return;
            }
            if (!mBackupFile.exists()) {
                if (!mFile.renameTo(mBackupFile)) {
                    Log.e(TAG, "Couldn't rename file " + mFile
                          + " to backup file " + mBackupFile);
                    mcr.setDiskWriteResult(false);
                    return;
                }
            } else {
                mFile.delete();
            }
        }
        try {
            FileOutputStream str = createFileOutputStream(mFile);
            if (str == null) {
                mcr.setDiskWriteResult(false);
                return;
            }
            XmlUtils.writeMapXml(mcr.mapToWriteToDisk, str);
            FileUtils.sync(str);
            str.close();
            ContextImpl.setFilePermissionsFromMode(mFile.getPath(), mMode, 0);
            try {
                final StructStat stat = Libcore.os.stat(mFile.getPath());
                synchronized (this) {
                    mStatTimestamp = stat.st_mtime;
                    mStatSize = stat.st_size;
                }
            } catch (ErrnoException e) {}
            mBackupFile.delete();
            mcr.setDiskWriteResult(true);
            return;
        } catch (XmlPullParserException e) {
            Log.w(TAG, "writeToFile: Got exception:", e);
        } catch (IOException e) {
            Log.w(TAG, "writeToFile: Got exception:", e);
        }
        if (mFile.exists()) {
            if (!mFile.delete()) {
                Log.e(TAG, "Couldn't clean up partially-written file " + mFile);
            }
        }
        mcr.setDiskWriteResult(false);
    }

这两者的差别是,commit 是同步操作,而apply 是异步实现的。在将writeToFile方法中,首先将当前文件重命名为备份文件,然后从当前文件中获取文件输出流,并将MemoryCommitResult中保存的备份数据,写入到文件输出流中。如果写入成功,则删除备份文件,返回true。如果写入失败,则删除当前文件,在下一次从备份文件中恢复过来。

QA

  • SP支持多线程吗?SP支持多进程吗?

两种都不支持,如果非要使用,会存在数据丢失的情况。

  • SP支持被其他APP 访问吗?

支持,但要访问的应用的Preference创建时指定了Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEABLE权限,否则都是访问不了的。

  • 自己创建一个同名同权限的文件放在对应的目录下,SP支持进行读写吗?

可以,但要求你的手机是root的机子,按照应用创建的方式,赋予对应的用户和用户组,还有响应的权限即可。如果遇到不成功的情况,可能是权限没有给到位,可以参考:http://bbs.elecfans.com/jishu_1654998_1_1.html

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SharedPreferences是Android中用于存储简单键值对数据的一种机制。它可以用于存储应用程序的配置信息、用户偏好设置等数据。以下是使用SharedPreferences的方法: 1. 获取SharedPreferences对象 可以通过Context类的getSharedPreferences()方法或者Activity类的getPreferences()方法来获取SharedPreferences对象。其中,getSharedPreferences()方法需要传入两个参数:SharedPreferences的名称和访问模式(MODE_PRIVATE表示只有当前应用程序可以访问该SharedPreferences对象);而getPreferences()方法则只需要传入访问模式,因为它会自动将当前Activity的类名作为SharedPreferences的名称。 例如: ``` SharedPreferences sp = getSharedPreferences("my_prefs", MODE_PRIVATE); ``` 2. 存储数据 可以通过SharedPreferences.Editor类的putXXX()方法来存储数据,其中XXX可以是Boolean、Float、Int、Long、String等类型。例如: ``` SharedPreferences.Editor editor = sp.edit(); editor.putString("username", "张三"); editor.putInt("age", 20); editor.putBoolean("isLogin", true); editor.commit(); ``` 3. 获取数据 可以通过SharedPreferences的getXXX()方法来获取存储的数据,其中XXX需要和存储时使用的类型一致。如果获取的键值对不存在,则会返回默认值。例如: ``` String username = sp.getString("username", ""); int age = sp.getInt("age", ); boolean isLogin = sp.getBoolean("isLogin", false); ``` 4. 删除数据 可以通过SharedPreferences.Editor类的remove()方法或者clear()方法来删除数据。其中,remove()方法需要传入要删除的键名,而clear()方法则会删除所有键值对。例如: ``` SharedPreferences.Editor editor = sp.edit(); editor.remove("username"); editor.clear(); editor.commit(); ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值