4

我有一些代码在 98% 的时间内有效,并且在我自己的测试期间 100% 有效,因此除了让用户设备遇到此问题外,我无法真正重现该问题。

我在 onPostExecute() 中所做的是设置这样的参数:

   SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences( AddProblemActivity.this);
            prefs.edit().putString("recent_problem_id", result ).commit();

然后进入下一个活动:

            Intent myIntent = new Intent(AddProblemActivity.this, ProblemActivity.class);
            AddProblemActivity.this.startActivity(myIntent);

然后尝试像这样在那里获取该参数:

SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences( 
              ProblemActivity.this);         

    // display a loading message before problem loads.
    String recent_problem_id = prefs.getString( "recent_problem_id" , null );

    if ( recent_problem_id == null )
    {
        // Sometimes it is null!            
    }

有谁知道为什么会这样?

谢谢!

4

7 回答 7

5

如果您尝试将数据传递给新活动,为什么不将其作为额外的字符串放在 Intent 中呢?然后,从新活动的意图中获取该字符串。如果您仍需要存储它,您可以在新活动的 onCreate() 将其从 Intent 中拉出后执行此操作。

Intent myIntent = new Intent(AddProblemActivity.this, ProblemActivity.class);
//Add results here
myIntent.putExtra("RecentProblemId", result);
AddProblemActivity.this.startActivity(myIntent);

然后,在新 Activity 的 onCreate 中,执行以下操作:

String recentProblemId = getIntent().getStringExtra("RecentProblemId");

现在,如果您仍需要存储此信息,请执行以下操作:

if(recentProblemId != null){
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences( 
              ProblemActivity.this);         
    prefs.putString("recent_problem_id",recentProblemId).commit();
}

我知道这并不能完全回答您关于为什么字符串并不总是致力于 onPostExecute() 中的首选项的问题。但是,在活动之间传递信息的最佳实践是通过 Intents 和 extras。

我对为什么它可能并不总是对某些用户有效的猜测是,他们的设备在新 Activity 启动并尝试从同一个文件中读取数据之前没有完成将数据写入共享首选项文件。希望这可以帮助。

于 2012-10-01T20:52:36.320 回答
2

首先,请参阅 Raghav Sood 的回答。
有一个微妙的时刻。您可能会开始执行 AsyncTask 而不是旋转设备。Activity 将被重新创建,并且在 PostExecute 中您将有错误的上下文,因此您的首选项将不会被保存。
如果是真的,你应该使用 onRetainNonConfigurationInstance() 来保存适当的任务实例。

于 2012-10-02T09:09:56.550 回答
1

我不确定这一点,但我认为问题可能是由于您传递的上下文不同。您AddProblemActivity首先使用的是 Context,然后是ProblemActivity. 尝试使用一组首选项,例如文件名:

SharedPreferences prefs = getSharedPreferences("MyPrefs", Context.MODE_PRIVATE);

请注意,getSharedPreferences()是来自 Context 的方法,因此您需要在 AsyncTask 中引用 Activity 或 Application Context 才能使用它。

于 2012-09-26T15:33:00.643 回答
1

看起来你的代码很好,没有理由不应该工作,唯一的原因是一些可能与设备相关的缺陷。我的想法是,由于共享首选项保存在本地存储中,因此在此过程中可能会出现问题。

正如评论中所建议的那样,添加设备类型日志是必须的,我建议您使用“ACRA”-http: //code.google.com/p/acra/,它可以以最少的努力为您提供详细的报告(请注意,您可以不必仅在应用程序崩溃时发送报告)。

看看这个线程,他展示了一个你可能也遇到的问题: SharedPreferences will not save/load in PreferenceActivity。如果是这种情况,解决方案将是手动处理在本地存储上保存这些持久数据或使用数据库解决方案。祝你好运 :)

于 2012-09-29T20:01:46.420 回答
1

我认为问题是由于当您尝试从第二个活动中访问共享首选项设置时尚未将其写入您的文件系统。您提到您从onPostExecute方法(AsyncTask也许?)编写设置。当您启动时,AsyncTask不能保证它会立即启动。唯一的保证是它将在后台线程中启动。平台可以并且将决定何时实际运行后台线程,具体取决于系统负载、文件系统块等。当您切换到第二个活动时,您可能AsyncTask还没有开始(因此onPostExecute尚未调用该方法)。

保存共享首选项在写入文件系统时很棘手。如果你不小心,你最终可能会阻塞主线程。该SharedPreferences.Editor对象还有一个apply方法,该方法将立即更新共享首选项的内存缓存(使更改立即可用)并启动后台线程以将实际值也保存到文件系统。所以我的建议是,如果你有可能,你应该尝试调用apply方法(从你的主线程)而不是commit(我假设的) a中的方法AsyncTask。该apply方法需要 API 级别 9 或更高。

供您参考:http: //developer.android.com/reference/android/content/SharedPreferences.Editor.html

编辑:

commit方法将根据写入操作的结果返回一个布尔值。您可以(应该?)检查该返回值,以便至少能够对失败采取正确的应对措施(例如显示“无法保存您的设置,请重试”toast 或其他内容)。

干杯,--dbm

于 2012-10-01T12:26:57.527 回答
0

我可能是错的。但我相信我的一个朋友曾经遇到过类似的问题。我被这个问题困了几个小时。结果在大约 30% 的情况下不起作用。我相信 onPostExecute() 在实例化 Intent 并调用活动时在单独的线程上运行。这是因为 AsyncTask 是在单独的线程上实现的。根据设备的不同,这将更有可能被调用而不是。我们的平板电脑很少发生,在智能手机上会更常见。

您可以通过调试应用程序并查看 AsyncThread 线程并查看何时进行调用来测试这一点。

是的,最好通过 putExtra() 发送变量。

我希望这可以帮助您理解为什么会发生这种情况。

于 2012-10-04T20:17:41.647 回答
0

SharePreferences 的提交操作是同步的,所以我认为您正在启动新意图这一事实不会影响它,唯一的问题是提交操作不是故障安全的,它可能会失败。

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

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

也许您应该检查该返回值以确保您设法保存了结果。

于 2012-10-06T07:53:39.287 回答