在 Android 代码优化中,SharedPreferences 的 "commit()" 方法会自动转换为 "apply()" 吗?

7
所以,我现在面临一个奇怪的问题。在我的Android应用程序中,我必须使用SharedPreferences.Editor().commit(),但是,如此处的文档所述, SharedPreferences实例在进程内是单例,如果您已经忽略了返回值,则可以将任何commit()实例替换为apply()。 您不需要担心Android组件生命周期及其与apply()写入磁盘的交互。框架确保在切换状态之前,来自apply()的正在飞行的磁盘写入完成。 基本上,如果您不使用返回值,则可以安全地将commit()替换为apply(),但是,如此处所述,并且在Android Studio中作为警告,两者之间的区别是commit()立即写入数据,但是apply()异步执行。 我的问题是,我正在更改应用程序中的语言,并希望在用户选择语言后重新启动应用程序。但是,当用户选择语言时,当前选择的语言被放置在 SharedPreferences 中。 现在的问题是:每当我使用 apply()而不是 commit()并使用代码here重新启动应用程序时,更改未写入磁盘,因为当应用程序重新启动时,它不会更改当前语言,因为 SharedPreference 的值没有更改,因为它不会立即写入磁盘。但是,每当我使用 commit()时,更改会立即写入,并且在应用程序重新启动时成功更改语言。 所以,问题是什么?
  1. 如果 commit()apply() 的代码由同一人编写,那么他们怎么能说使用 apply() 完全安全而不是 commit() 呢?因为它们之间存在很大的区别,commit() 立即写入数据,而 apply() 则在后台执行。

  2. 如果我构建我的apk,如果我没有使用返回值,commit() 是否会在代码优化中被 apply() 取代呢?(我知道可以通过构建应用程序的发布版本来了解这一点,但我仍然不确定,因为当我使用 apply() 时,它经常只有1/10的机会实际上从SharedPreference更改值)

注:

  1. 我知道如何使用 apply() 并使我的应用程序正常工作,也许我需要在重新启动应用程序之前添加一些延迟?但我不确定它将如何工作,因为它仍然需要一些时间才能真正将数据写入磁盘,并且我目前没有看到任何检查 SharedPreference 值是否实际更改的方法,以便我可以在值更改后安全地重新启动。
1个回答

6
问题是,使用Runtime.getRuntime().exit(0)System.exit(0)将会终止进程,因此没有计划的异步任务将会执行。 如果您不打算更改重启代码,则应该保留commit而不是apply,并抑制警告。
  1. 可以安全地假定该语句有效,因为通常情况下不应调用exit(0)
  2. 没有理由假设commit会自动替换为apply。如果您想确保,请使用返回值。

Android Studio 给出了一个大警告,说用 apply 替换 commit 是安全的,所以也许它会替换掉?另外,我如何在不使用 System.exit(0) 的情况下退出我的应用程序?因为我正在使用那里给出的第二种方法,而不是提到的第一种方法。 - Vedprakash Wagh
1
Android Studio不希望使用exit(0)来终止进程。这可能是唯一一种情况,其中用apply替换commit是不安全的。 - tynn
1
正如@tynn所说,Android Studio的警告只是一个警告,用于提醒潜在问题;在这种情况下,您正在执行异常操作(调用OS System.exit方法),该操作将终止进程,这不是共享首选项应用程序方法在正常情况下期望发生的事情,因此,抑制警告是可以的;我会留下一条注释,向下一个阅读该代码的可怜人解释它。 - Martin Marconcini
1
是的,你说得对,但是接下来就会遇到重启应用程序的问题。如果不使用exit(0),我该如何在更改语言后完全重启应用程序呢? - Vedprakash Wagh
1
但是,正如您所发现的那样,这样做会产生副作用和后果。也就是说:框架没有预料到并且没有设计/编程来处理的事情。 :) - Martin Marconcini
显示剩余8条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,