Android的SharedPreferences commit()什么时候返回false?

时间:2015-05-27 07:04:12

标签: android sharedpreferences

在我的应用中,我将一些数据存储在SharedPreferences中 - 它可以根据需要运行。 现在我想为某些不正确的情况创建日志消息。

我成功处理了首选项为空或在加载时抛出异常的情况。 保存值时唯一可以显示的错误是commit()返回false - 我不知道为什么会发生这种情况以及在这种情况下应该做些什么。

所以我的问题是: commit()方法何时返回false? 在那种情况下我该怎么办? 一个可能的解决方案是一次又一次地呼叫commit()(类似while (!editor.commit()) {})吗?

4 个答案:

答案 0 :(得分:11)

  

虽然(!editor.commit()){;}可以成为成功的解决方案吗?

'commit'操作是同步的并且在UI线程上执行,因此,如果每次尝试执行commit时都会发生一些不可恢复的错误,那么您将使用此代码阻止整个UI线程,用户将看到ANR。不好。
另一方面,'apply'是异步的,因此即使你将无限期地执行它,它也无法阻止UI线程。
文档对“提交”操作可能失败的说法很少(请查看hereherethere)。首选项存储在存储在内部存储器中的xml文件中,因此可能的一个失败可能是损坏的xml文件。第二个可以在documentation中找到:

  

请注意,当两个编辑者同时修改首选项时    时间,最后一个调用commit wins。

关于损坏的文件几乎无法做到,而且,不要尝试同时修改来自不同位置的首选项。 :)

答案 1 :(得分:11)

首先,你永远不想做: while(!editor.commit()) {;}。如果你想重试一次提交,你会做几次,而不是永远循环。

关于commit()何时返回-1: commit()和apply()都会对内存进行更改,然后进行调用以将更改写入磁盘(per source)。 commit()等待磁盘写入返回以返回结果。因此,您的问题的答案是:“将偏好状态保存到磁盘时,您的特定commit()调用将失败。”由于更改反映在内存中,因此在您尝试写入磁盘之前或之后,可能会或可能不会通过另一个commit()或apply()调用将其写入磁盘(想想赛车线程)。由于没有代码可以回滚内存更新而SharedPreferences是单例(per source),即使应用中的其他组件没有保存到磁盘,它们也会看到您的更改。

总之,循环几次(不是永远)以确保提交()写入磁盘似乎很好,让你通过一个间歇性的I / O问题,但它将是一个罕见的基于I / O的情况,它失败。如果您需要完美的提交范围,您可能需要重新读取磁盘以验证每个commit()调用,这些调用具有性能影响并且除了一小部分情况外都是过度的。

答案 2 :(得分:5)

如果在保存数据时出现问题,

commit()可能会返回false。

查看commit()apply()之间的区别,以获得更清晰的想法(取自this site

  

应用()

     

这会立即将数据保存到内存中并保存数据   磁盘在一个单独的线程上。所以没有机会阻挡主力   线程(你的应用程序不会挂起)。

     

这是首选技术,但此后才可用   Gingerbread(API 9,Android 2.3)。

     

提交()

     

调用此方法会将数据保存到文件中,但过程是   在调用它的线程中执行,停止其他所有操作   直到保存完成。成功完成后返回true,   失败时假。

     

如果您需要确认保存成功,请使用commit()   数据或者您是否正在为姜饼设备开发。承诺()   自API 1以来一直可用

答案 3 :(得分:3)

我将从另一个角度完全接近这个问题。

有几种方法可以解决这个问题。

我做的是当我的程序第一次运行时,我  将我的共享首选项值初始化为测试值,以便检查是否存在 已被改变。

例如:

editor.putInt("key", -1);

然后在我正在检索首选项值的活动中:

int mySavedInt = this.pref.getInt("key", howIgetMyInt)
if(mySavedInt==-1){
    // I know it's not my saved int :) and hasn't been set.
}

或者实际使用共享首选项本身来确定共享首选项 您正在尝试验证已更新。

例如

String getStatus = pref.getString("checkMySharedPreferences", "nil");
    if (getStatus.equals("true")) {
        // DO something.
    } else {
        Toast.makeText(this, "Set your preferences",
                Toast.LENGTH_SHORT).show();
    }

然后,当您设置共享偏好设置时,您可以将此值设置为" true":

editor.putString("checkMySharedPreferences", "true");
editor.commit();

另一个建议是确保在更新共享首选项之前验证任何数据。  这样,如果数据无效,则不会设置共享首选项。

if(my data is valid){
    my shared preferences
    commit
}

最后的建议是进行循环检查(因为您在此过程中不安全)以及获取共享首选项的数据并提交它。检查用户输入是否等于新的共享首选项。虽然我不认为这是必要的。

要记录这些事件,只需在适用的位置添加日志行。

另外,只是旁注,我认为如果没有设置异常,抛出异常一定是好习惯,我相信管理程序流程可以通过条件语句更好地处理显然会出现runtime错误。保存错误处理以验证用户输入。