前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SharedPreference 的commit和apply

SharedPreference 的commit和apply

作者头像
PhoenixZheng
发布2018-08-07 16:12:56
1.1K0
发布2018-08-07 16:12:56
举报
文章被收录于专栏:Phoenix的Android之旅

SharedPreference是Android开发中经常用到的一个数据持久化类, 我们可以把一些需要持久化的数据放到一个指定的 Preference文件中,并持久化到磁盘上以xml形式存储起来。 这个xml文件对于开发者来说基本算是透明的,开发者只需要面对 Preference 所需要的文件名。

关于SharedPreference的原理可以分读和写两部分理解,今天我们先说关于写的这部分。 而关于读就相对比较复杂一些,这里面会涉及到线程和进程等各方面的细节问题,后面我们在仔细分析。

commit和apply两个方法

总所周知Android提供了这两个方法来写入数据,一般来说写入数据的步骤是这样的

代码语言:javascript
复制
SharedPreferences pref = mContext.getSharedPreferences(Const.SHARED_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
Gson gson = new Gson();
String json = gson.toJson(info);
editor.putString(Const.PREFER_NAME, json);
editor.apply();
//editor.commit();

这里先给结论, · apply的写磁盘是异步行为 · commit的写磁盘是同步行为 · 两者在写磁盘前都会先同步的写到内存缓存中

apply 流程

首先要理解 SharedPreference有一个两级缓存系统,包括了内存缓存和磁盘缓存。 它用一个 HashMap对象mMap保存内存缓存,每次写的时候都会先更新这个对象的数据。 下面是调用 apply的简化后的源码

代码语言:javascript
复制
public void apply() {
  final MemoryCommitResult mcr = commitToMemory();
  final Runnable awaitCommit = new Runnable() {
          public void run() {
              try {
                  mcr.writtenToDiskLatch.await();
              } catch (InterruptedException ignored) {
              }

              if (DEBUG && mcr.wasWritten) {
                  Log.d(TAG, mFile.getName() + ":" + mcr.memoryStateGeneration
                          + " applied after " + (System.currentTimeMillis() - startTime)
                          + " ms");
              }
          }
      };
  ....
  Runnable postWriteRunnable = new Runnable() {
        public void run() {
            awaitCommit.run();
            QueuedWork.removeFinisher(awaitCommit);
        }
    };
  SharedPreferencesImpl.this.enqueueDiskWrite(mcr, postWriteRunnable);
  notifyListeners(mcr);
}

逐句分析, 先调用了commitToMemory()同步修改后的数据到内存中, 然后用Runnable把写磁盘的操作包了起来,并放到一个队列中进行异步处理, 最后通知监听者数据写入完成(因为并发的原因可能不一定写完磁盘)

下面是commit的代码

commit 流程
代码语言:javascript
复制
public boolean commit() {
    long startTime = 0;

    MemoryCommitResult mcr = commitToMemory();// <-- 一样的调用

    SharedPreferencesImpl.this.enqueueDiskWrite(
        mcr, null /* sync write on this thread okay */);
    try {
        mcr.writtenToDiskLatch.await();
    } catch (InterruptedException e) {
        return false;
    } finally {
        if (DEBUG) {
            Log.d(TAG, mFile.getName() + ":" + mcr.memoryStateGeneration
                    + " committed after " + (System.currentTimeMillis() - startTime)
                    + " ms");
        }
    }
    notifyListeners(mcr);
    return mcr.writeToDiskResult;
}

对比apply()的代码就比较明显了, 虽然在调用 commitToMemory()的时机上是一样的,但是后面写入磁盘是个同步操作, 这也就导致了在主线程写入数据可能发生anr的问题。

总结

apply()和commit()是异步和同步的差异, 两者都会先写入到内存缓存, 在主线程写入数据建议用 apply(), 而需要调用 commit()的话就建议在子线程中了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-06-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Android每日一讲 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • commit和apply两个方法
  • apply 流程
  • commit 流程
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档