ChatGPT解决这个技术问题 Extra ChatGPT

SharedPreferences 中的 commit() 和 apply() 有什么区别

我在我的 Android 应用程序中使用 SharedPreferences。我正在使用来自共享偏好的 commit()apply() 方法。当我使用 AVD 2.3 时,它没有显示错误,但是当我在 AVD 2.1 中运行代码时,apply() 方法显示错误。

那么这两者有什么区别呢?并且仅使用 commit() 可以毫无问题地存储首选项值吗?

这已经有一年了,但无论如何我还是要对此发表评论,尽管这可能很明显,但没有一个答案能说明这一点:apply() 将异步执行磁盘 I/O,而 commit() 是同步的。所以你真的不应该从 UI 线程调用 commit()
值得注意的是,当使用多个 SharedPreferences.Editor 对象时,最后一个调用 apply() 的对象获胜。因此,如果您确保您的应用程序只使用一个 SharedPreferences.Editor,则可以安全地使用 apply() 代替 commit()
根据 Android Studio Lint 警告:commit() 将立即同步保存数据。但是,apply() 将异步保存它(在后台),从而提高一些性能。这就是为什么如果您不关心它的返回类型(如果数据保存成功与否), apply() 优于 commit() 的原因。
有没有办法在使用 commit() 时禁用 Lint 警告?

M
Micer

apply() 是在 2.3 中添加的,它提交而不返回指示成功或失败的布尔值。

如果保存有效,commit() 返回 true,否则返回 false

添加 apply() 是因为 Android 开发团队注意到几乎没有人注意到返回值,因此 apply 速度更快,因为它是异步的。

http://developer.android.com/reference/android/content/SharedPreferences.Editor.html#apply()


这个答案是正确的,但我猜@spacemanaki 上面的评论也是正确的,其中包含有价值的信息
commit() 立即将其数据写入持久存储,而 apply() 将在后台处理它。
它会产生竞争条件吗?
如果我用 apply() 写了一些东西并尝试在之后立即阅读它会发生什么?阅读是否保证能给我最新的价值?文档说,如果在您触发 apply() 后发生另一个 commit(),则 commit() 将阻塞,直到 apply() 持久化到磁盘,这清楚地表明在“写入”操作时不会发生此问题,但是如果您在之后立即写作和阅读呢?从我的测试中,返回了最新的值,但我想知道这是否 100% 保证。
用 apply() 替换任何 commit() 实例是安全的,请参阅 developer.android.com/reference/android/content/…
L
Lukas Knuth

tl;博士:

commit() 同步写入数据(阻塞调用它的线程)。然后它会通知您操作成功。

apply() 安排异步写入的数据。它不会通知您操作是否成功。

如果您使用 apply() 保存并立即通过任何 getX 方法读取,则将返回新值!

如果您在某个时候调用了 apply() 并且它仍在执行,那么对 commit() 的任何调用都将阻塞,直到所有过去的应用调用和当前的提交调用都完成。

SharedPreferences.Editor 文档中的更深入信息:

与将其首选项同步写入持久存储的 commit() 不同,apply() 立即将其更改提交到内存中的 SharedPreferences 但开始异步提交到磁盘,并且您不会收到任何失败的通知。如果此 SharedPreferences 上的另一个编辑器在 apply() 仍未完成时执行常规 commit(),则 commit() 将阻塞,直到所有异步提交以及提交本身完成。由于 SharedPreferences 实例是进程中的单例,因此如果您已经忽略了返回值,则可以安全地将任何 commit() 实例替换为 apply()。 SharedPreferences.Editor 接口预计不会直接实现。但是,如果您之前确实实现了它并且现在收到有关缺少 apply() 的错误,您可以简单地从 apply() 调用 commit()。


这是一个更好的答案,因为它提到 apply() 是异步的,并且挂起的写入会阻止未来对 commit() 的调用。
J
JoseLSegura

我在使用 apply() 而不是 commit() 时遇到了一些问题。如前在其他响应中所述,apply() 是异步的。我遇到的问题是,对“字符串集”首选项的更改永远不会写入持久内存。

如果您“强制保留”程序,或者在我使用 Android 4.1 安装在我的设备上的 ROM 中,当进程由于内存需求而被系统杀死时,就会发生这种情况。

如果您希望自己的偏好生效,我建议使用“commit()”而不是“apply()”。


您确定您的问题与并发线程无关吗?发送 apply() 后,必须等待一段时间才能读取添加的内容,否则 UI 线程会在 apply() 的工作线程提交更改之前尝试读取。
@JoseLSegura - 文档另有建议:developer.android.com/intl/ja/reference/android/content/…“您无需担心 Android 组件生命周期及其与 apply() 写入磁盘的交互。该框架确保在切换之前完成来自 apply() 的飞行中磁盘写入状态。”我想知道您所看到的是否是 Android 中的错误,如果是,是否已在较新版本中修复。
使用库“ProcessPhoenix”重置我的应用程序时,我遇到了同样的问题。我在执行重置之前保存了首选项,并且“应用”不起作用。
M
Mustafa

使用应用()。

它立即将更改写入 RAM,然后等待并将其写入内部存储(实际的首选项文件)。提交将更改同步并直接写入文件。


N
Nurlan Sofiyev

commit() 是同步的,apply() 是异步的

apply() 是无效函数。

如果新值已成功写入持久存储,则 commit() 返回 true。

apply() 保证在切换状态之前完成,您无需担心 Android 组件生命周期

如果您不使用从 commit() 返回的值并且您正在使用主线程中的 commit(),请使用 apply() 而不是 commit()


为了清楚起见,那些“切换状态”是什么?
@carloswm85 2 岁但要澄清:通常“切换状态”意味着诸如方向改变之类的事件。
D
Dan Getz

文档很好地解释了 apply()commit() 之间的区别:

与将其首选项同步写入持久存储的 commit() 不同,apply() 会立即将其更改提交到内存中的 SharedPreferences,但会开始异步提交到磁盘,并且不会通知您任何失败。如果此 SharedPreferences 上的另一个编辑器在 apply() 仍未完成时执行常规 commit(),则 commit() 将阻塞,直到所有异步提交以及提交本身完成。由于 SharedPreferences 实例是进程中的单例,因此如果您已经忽略了返回值,则可以安全地将任何 commit() 实例替换为 apply()。


C
Chanaka Weerasinghe

commit() 和 apply() 的区别

当我们使用 SharedPreference 时,我们可能会对这两个术语感到困惑。基本上它们可能是相同的,所以让我们澄清一下commit()和apply()的区别。

1.返回值:

apply() 提交时不返回指示成功或失败的布尔值。 commit() 如果保存有效,则返回 true,否则返回 false。

速度:

apply() 更快。 commit() 较慢。

异步与同步:

apply():异步 commit():同步

原子:

apply():原子 commit():原子

错误通知:

apply():否 commit():是


apply()commit()“快”多少?它们本质上代表将被放入线程的 Looper 中的相同任务。 commit() 将该任务置于主 Looper 中,而 apply() 将其置于后台,从而使主 Looper 没有磁盘 I/O 任务。
与将其首选项同步写入持久存储的 commit() 不同,apply() 会立即将其更改提交到内存中的 SharedPreferences,但会开始异步提交到磁盘,并且不会通知您任何失败。如果此 SharedPreferences 上的另一个编辑器在 apply() 仍然未完成时执行常规 commit(),则 commit() 将阻塞,直到所有异步提交完成以及提交本身参见 DOC developer.android.com/reference/android/content/…
V
Vladimir Ivanov

来自 javadoc:

与将其首选项同步写入持久存储的 commit() 不同,apply() 立即将其更改提交到内存中的 SharedPreferences 但开始异步提交到磁盘,并且您不会收到任何失败的通知。如果此 SharedPreferences 上的另一个编辑器在 > apply() 仍然未完成时执行常规 commit(),则 commit() 将阻塞,直到所有异步提交以及提交本身都完成