我在我的android应用程序中使用SharedPreferences。我同时使用commit()和apply()方法共享首选项。当我使用avd2.3时,它显示没有错误,但当我在avd2.1中运行代码时,apply()方法显示错误。

这两者有什么区别呢?通过只使用commit()我可以存储首选项值没有任何问题吗?


当前回答

在使用web API时,我注意到apply()在注销前使用共享首选项时的主要缺点。

请看下面的场景: 用户登录和令牌(用于自动重新登录)随POST一起传递。

SharedPreferences preferences = App.getContext().getSharedPreferences("UserCredentials", Context.MODE_PRIVATE);

SharedPreferences.Editor editor = preferences.edit();

editor.putString("TOKEN",token);

editor.apply();

令牌在所有会话中都可用,没有问题,自动重新记录在整个状态中没有任何进一步的问题。

在编写注销函数时,我清除了共享首选项,如下所示

SharedPreferences preferences = App.getContext().getSharedPreferences("UserCredentials", Context.MODE_PRIVATE);

SharedPreferences.Editor editor = preferences.edit();

editor.clear();

editor.apply()

简而言之,你可以这样写:

preferences.edit().clear().apply()

为了确保我清除了缓存,我会在注销前Log,和preferences.getString("TOKEN");显示为null。

在重新启动主活动(因为它是从登录片段开始的)-我会再次检查令牌,使用:

SharedPreferences preferences = App.getContext().getSharedPreferences("UserCredentials", MODE_PRIVATE);
        
String retrievedToken = preferences.getString("TOKEN",null); // Second param = default value

Log.d(TAG, "RETRIEVING TOKEN: " + retrievedToken);

令牌实际上重新出现,即使令牌在注销之前肯定已经被清除。

(导致注销-> '登录-使用-令牌循环)

只有在添加了editor.commit()之后;设置和清除令牌实际上都将永久消失。

注意,我使用了模拟器。

这种行为实际上是有道理的,因为内存中的存储被更新了,但异步调用在应用程序重新启动之前从未进行过。

因此commit ();将迫使应用程序等待(同步)与实际的后续命令,如system.exit()等,而apply()可以很好地失败,如果其他命令将强制应用程序中的某个状态改变。

为了确保你找到了所有正确的点,你可以同时使用apply()和commit()。

其他回答

Apply()是在2.3中添加的,它提交时不返回一个表示成功或失败的布尔值。

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

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

http://developer.android.com/reference/android/content/SharedPreferences.Editor.html应用()

从javadoc:

与commit()不同,commit()将其写入 首选项输出到持久存储 同时,apply()提交它的 内存中的更改 SharedPreferences,但是 启动对磁盘的异步提交 我不会通知你的 失败。如果这个SharedPreferences上的另一个编辑器执行常规的commit(),而> apply()仍然未完成,commit()将阻塞,直到所有异步提交以及提交本身完成

使用适用于()。

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

tl; diana:

commit() writes the data synchronously (blocking the thread its called from). It then informs you about the success of the operation. apply() schedules the data to be written asynchronously. It does not inform you about the success of the operation. If you save with apply() and immediately read via any getX-method, the new value will be returned! If you called apply() at some point and it's still executing, any calls to commit() will block until all past apply-calls and the current commit-call are finished.

更多深入的信息来自SharedPreferences。编辑文档:

Unlike commit(), which writes its preferences out to persistent storage synchronously, apply() commits its changes to the in-memory SharedPreferences immediately but starts an asynchronous commit to disk and you won't be notified of any failures. If another editor on this SharedPreferences does a regular commit() while a apply() is still outstanding, the commit() will block until all async commits are completed as well as the commit itself. As SharedPreferences instances are singletons within a process, it's safe to replace any instance of commit() with apply() if you were already ignoring the return value. The SharedPreferences.Editor interface isn't expected to be implemented directly. However, if you previously did implement it and are now getting errors about missing apply(), you can simply call commit() from apply().

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

Unlike commit(), which writes its preferences out to persistent storage synchronously, apply() commits its changes to the in-memory SharedPreferences immediately but starts an asynchronous commit to disk and you won't be notified of any failures. If another editor on this SharedPreferences does a regular commit() while a apply() is still outstanding, the commit() will block until all async commits are completed as well as the commit itself. As SharedPreferences instances are singletons within a process, it's safe to replace any instance of commit() with apply() if you were already ignoring the return value.