SharedPreferences在PreferenceActivity中无法保存/加载

14

编辑:下面描述的问题是由于非编码相关的非常奇特的设备问题引起的。

我有一个PreferenceActivity,在其中有许多checkBoxPreferences。 checkBoxPreference应该保存默认的共享首选项文件,然后在我打开应用程序时再次调用它以更新UI。

但这并不像它应该的那样发生。 如果我关闭应用程序并重新打开它,我的值会保持正常,但是如果我使用任务管理器结束应用程序或者在应用程序没有运行时重新启动手机,则会再次调用defaultValues。

因此,在我的onResume()中创建了一个SharedPreference来进行测试。

SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());

然后我检查那个sharedpreference中是否有一个键。

pref.contains("myCheckBoxPreference");

当我关闭应用再重新打开时,它返回true。但如果我使用任务管理器强行关闭或者重启手机后再打开,那么就会返回false。

因此,我尝试手动设置SharedPreference。

SharedPreferences.Editor editor = pref.edit();
editor.putBoolean("myCheckBoxPreference", myCheckBoxPreference.isChecked());
editor.commit();

之后我在checkboxpreference值改变时调用了它。我还尝试在onStop和onPause中调用它。但是,如果我关闭应用程序并重新打开它,pref.contains返回true,但如果我关闭手机并重新打开它,则返回false。

所以我尝试使用SharedPreferences文件。

在类声明中:

public static final String PREFS = "prefs";

然后在onResume()方法中:

SharedPreferences pref = this.getSharedPreferences(PREFS, 0);

同样的行为,如果我只是关闭应用并重新打开它,pref.contains仍然返回true,但是如果我关机然后重新开机,它将返回false。

然后我尝试将myCheckBoxPreference的键值更改为与CheckBoxPreference的xml键不匹配的值,但它仍具有相同的效果。

我还卸载了手机上的应用程序,然后关闭手机并重新打开,然后重新安装,但仍然具有相同的效果。


我很想看到您在测试时的logcat输出,以及完全在onCreate中编写的确切测试用例,该测试用例仅打开首选项并保存一个值,然后在下次启动程序时读取它,以及您的MYPREFS常量的内容。您真的无法读取偏好设置吗?还是当您启动PreferenceActivity子类时,它们只是不出现在DialogPreference GUI中? - Thomas Dignan
我想发布那个,但我对Android很新,实际上不知道如何使用logcat,我只是制作Toast通知来告诉我事情是否正确。(而且我觉得这更有用,因为我可以在应用程序运行时轻松查看Toast。但是,使用Toast通知时,它说布尔值为false,而我之前将其保存为true。并且当从主活动和调用sharedpreference的另一个活动进行烤面包时会发生这种情况。而且它似乎不是GUI更新问题,因为在电源循环手机之前它可以工作。 - Reed
在Android 2.3.7上观察到相同的行为。不过我注意到只需要旋转设备,就可以销毁活动并使用新的偏好重新触发onCreate - ccpizza
1
@jakar 在加载设置后添加类似于 Log.d("prefstest", "Pref == " + pref); 的代码行,它将把数据输出到 Eclipse 的 logcat 输出中。在终端窗口上键入 adb logcat 也可以读取。非常方便。 - mikebabcock
7个回答

7
我刚刚解决了这个问题,我非常确定。在我的代码中没有错误,也没有任何与我的应用程序有关的问题(无论如何,我不相信会有问题)。
我创建了一个名为“testproj”的新项目,然后将设置PreferenceActivity中的所有代码都复制到TestprojActivity中,并将其所依赖的xml代码复制到TestProj的main.xml中。
然后,我在三星Captivate上安装了TestProj,在RAM管理中清除了RAM,并更改了设置,然后设置就保持不变了。然后我重新启动了手机,设置仍然像我配置的那样。
它们在我使用以下命令手动设置它们时仍然保持不变:
PreferenceManager.getDefaultSharedPreferences();

无需手动保存到SharedPreferences,即可完成。

由于这不是我的手机,所以我还没有尝试过,但我认为恢复出厂设置可以完全修复它。编辑:我已经在新的三星 Captivate 和 Samsung infuse 上进行了测试,并且它可以正常工作。

我浪费了很多时间来弄清楚这一点,希望它能帮助其他人 :)


听起来像是Paul在下面的回答相关。 - David Snabel-Caunt
我不知道三星Captivate是三星Galaxy S的变种。看起来David Caunt关于这个问题在那个型号上的看法是正确的。 - Paul Lammertsma
1
8年后,我浪费了好几个小时想弄清楚我的代码有什么问题...结果发现只是设备出了问题。 - Luke Needham

6

我在三星Galaxy S上遇到了一个可能类似的问题,偏好设置XML文件的权限出现了某种变化/损坏。

日志显示某个主机进程无法读取该文件,导致所有设置重置为默认值。我不记得确切的错误消息,但大致是“拒绝对/path/to/preferences/file.xml的许可”。

对我来说,解决办法是通过“设置”,“应用程序”,“管理应用程序”,“我的应用程序”,“删除数据”来删除应用程序数据。这将删除与该应用程序相关联的首选项文件,问题立即消失。

我认为这是一个孤立事件,因为我在各种Android设备(包括Galaxy S II)上没有再次遇到它。


奇怪的是,当我进入应用程序管理时,“删除数据”选项是灰色的,并且显示“数据.......0.00B”。TestProj也出现了完全相同的情况,但是手机将在下周更换,所以我很快就能真正测试它了。 - Reed
Galaxy S上的一个常见问题 - 首选项权限损坏的错误。我收到了一些用户的报告。 - David Snabel-Caunt
@David-Caunt 很高兴知道这一点;我担心自己在做一些愚蠢的事情。 - Paul Lammertsma
我在几个论坛上看到过这个问题的报告,重新安装通常可以解决。三星方面没有任何消息,但他们的代码已经被许多开发人员批评。 - David Snabel-Caunt
我在一个三星Infuse手机上遇到了一个类似问题的用户,出现以下错误:尝试读取/dbdata/databases/com.munzee.android.client/shared_prefs/MunzeePrefs.xml偏好文件时未获取权限。我尝试将MunzeePrefs.xml文件名更改为UID,但似乎权限是设置在路径中的FQN上的。有没有什么建议如何解决这个问题?卸载/重新安装应用程序无法解决该问题。建议给用户的唯一解决方案可能是恢复出厂设置。有没有想报告问题给三星的地方? - Chrispix
唯一想到的方法就是对手机进行root,然后手动删除该文件。 - Paul Lammertsma

3
在客户的主要测试设备上,我遇到了同样的问题。使用的设备是三星Galaxy S,SDK级别为8(2.2.1)。
奇怪的行为是,要么SharedPreferences没有保存,要么就像恢复出厂设置后一样过于持久,也就是说,在重新安装应用程序后它们没有被删除。
由于当前2.2.x的distribution以及销售的数百万三星Galaxy S设备数量,这个问题发生的概率是相当大的。
因此,实现一个解决方案来保存偏好设置可以被认为是至关重要的。
为了收集详细的特征以尖锐地隔离这个解决方案,每个面对这个问题的人都可以提供相应的内核版本(System.getProperty("os.version")吗?
我想的是这样的:
// !! I know that 2.6.32.9 is not yet correct. This would be a false positive !!
if ((System.getProperty("os.version").startsWith("2.6.32.9"))
    && (android.os.Build.DEVICE.contains("GT-I9000")))
    useInternalStorage();
else
    useSharedPreferences();

我可以在准备好并有人感兴趣时,在此处发布真实的代码。

编辑:一些额外的信息:

出现该问题的设备:

    属性                             | 值
    ---------------------------------+------------------------------------
    Build.DEVICE                     | "GT-I9000T"
    Build.VERSION.INCREMENTAL        | "UBJP9"
    Build.VERSION.RELEASE            | "2.2.1"
    Build.VERSION.SDK                | 8
    System.getProperty("os.version") | "2.6.32.9"
    

未出现该问题的类似设备:

    属性                             | 值
    ---------------------------------+------------------------------------
    Build.DEVICE                     | "GT-I9000"
    Build.VERSION.INCREMENTAL        | "AOJP4"
    Build.VERSION.RELEASE            | "2.2"
    Build.VERSION.SDK                | 8
    System.getProperty("os.version") | "2.6.32.9"
    


我现在使用的设备可以正常工作,但如果在你的测试设备上调用editor.clear().commit()来清除该偏好文件中的所有值,那么这些值是否能够成功保存?另外,如果将偏好文件的名称更改为其他名称会发生什么情况?我之前没有尝试过这些步骤,而且我也不再拥有一个出故障的Galaxy S手机了。 - Reed

3

在设置值之前,请尝试清除编辑器。我遇到了同样的问题,这对我有用。 示例:

Editor e = PreferenceManager.getDefaultSharedPreferences(getParent()).edit();
e.clear();
e.putStringSet(key, value);

谢谢您的输入,但我遇到的问题实际上是设备问题。除了设备或操作系统错误之外,我描述的问题不存在任何原因。此外,您不必clear()以写入新值,除非您只是想将应用程序恢复为其默认状态。 - Reed

0
我也遇到了保存和检索数据的问题。我将我的保存和加载代码放在扩展Application的类中,因为我想要一个数据的单一实例。我可以看到字符串被保存了,LogCat中没有错误,但是当我尝试加载它时,再次没有错误,我的字符串为空。我从未检查过数据是否实际进入文件,所以我不知道保存或加载或两者都失败了。
我的代码大致如下:(comboToSave只是由Gson从简单数据类生成的字符串)
在一个保存方法中:
  SharedPreferences sharedPref = activity.getPreferences(Context.MODE_PRIVATE); 
  SharedPreferences.Editor editor = sharedPref.edit();
  editor.putString(getString(R.string.prefCombos), comboToSave); 
  editor.commit();

在另一种加载方法中:
  SharedPreferences sharedPref = activity.getPreferences(Context.MODE_PRIVATE);
  String loadedComboText = sharedPref.getString(getString(R.string.prefCombos), "");

在经过大量思考和不知道该怎么做之后,我更改了检索sharedPref值的代码:

SharedPreferences sharedPref = activity.getPreferences(Context.MODE_PRIVATE);

变成了

SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());

这里有一些关于两者之间差异的更多信息(尽管在我的情况下似乎完全相同)

然而,在我的Galaxy S3上的结果仍然是相同的。但是,在其他设备上进行测试,包括虚拟设备,都可以正常工作。

在代码的第一个版本中,我从调用活动中传递了Activity;从收集用户最终数据的活动中保存,从我的主要活动中加载,以便在应用程序启动时准备好它。

昨晚我试着卸载应用程序并重新安装,重启设备,但都没有效果。

我现在已经将保存和加载方法从应用程序类移动到完整输入的活动中,即加载和保存代码现在在同一个活动中。 我已经使用两个不同的代码变体进行了测试,它们都能够正常工作。 我可以恢复我所保存的内容。 然后我将所有代码移回应用程序类,它也可以正常工作; 这使我相信,在安装/卸载时,我以某种方式设法使它正常工作。

重点是:代码是正确的 - 如果不起作用,则可能是设备和/或设置出了问题

0

0

我有同样的问题,而且我已经遭受了一段时间,最终我找到了解决方案, 而且它非常简单,只需传递活动的直接引用,不要使用任何通用上下文。

public SessionManagment(Activity mContextActivity){
//  this.contextActivity = mContext;
    sharedPrefSession =  mContextActivity.getSharedPreferences(
            Constants.SHARED_PREFERANCES_LIGHT_TIGER_SESSION_FILE_NAME, 
            Context.MODE_PRIVATE);

}//enden constructor 

上面的代码是我为会话管理编写的类的构造函数,当我在主ActivityFramgment中的AsyncTask中调用它时,我会这样调用它

SessionManagment sessionManagment = new SessionManagment(referanct2thisActivity);

其中 referanct2thisActivity 在片段活动的 "onCreate" 函数中定义,如下所示

referanct2thisActivity = this;

希望这对将来的其他人有所帮助。

我感谢你的帮助,但在我的情况下实际问题是由于一个有故障的设备引起的。 - Reed

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