从Bundle中删除条目(即extras)似乎不能与后退button结合使用

我有一个收听短信的BroadcastReceiver“。 如果消息来自某个发件人,则BroadcastReceiver使用以下代码启动我的应用程序:

final Intent activityIntent = new Intent(context, MainActivity.class); activityIntent.putExtra("smsChallenge", smsText); activityIntent.putExtra("smsSenderNumber", senderMobilNumber); activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); activityIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); context.startActivity(activityIntent); 

在我的应用程序的MainActivity(即在onCreate() ),我提取的意图smsChallenge出于意图和删除它后面的提取与下面的代码:

 Bundle extras = getIntent().getExtras(); if (extras != null) { smsChallenge = extras.getString("smsChallenge"); extras.remove("smsChallenge"); } 

所以我的应用程序从SMS开始,运行良好…但是,如果我select按下BACKbutton并重新启动应用程序(即通过Taskmanager),值smsChallenge仍然在捆绑extras 。 这意味着,我重新启动的应用程序认为,它是重新启动,因为一个新的短信,这是不正确的… …

当使用BACKbutton并重新启动应用程序时,任何想法为什么从捆绑中删除键值似乎不工作?

Solutions Collecting From Web of "从Bundle中删除条目(即extras)似乎不能与后退button结合使用"

我认为你不能修复这种行为,因为当你访问意图的时候,os已经保存了以后通过最近的应用程序启动的意图。

  1. 您可以添加一个标志来从最近的应用程序中删除,但这样的应用程序将不会出现在最近的应用程序。
  2. 在永久存储器中添加在MainActivity中处理的最后一个sms,然后在onCreate中进行检查,放弃已经处理过的短信的意图。
  3. 最终的解决scheme是根本不发送数据。 例如,将它们保存在“未决”持久性存储中。 当你的MainActivity启动时,让它检查待处理的东西,并清除这个未决项目。

例如,持久存储可以是SharedPreferences。

我build议你使用2,但是你应该计数收到的短信,并使用该计数器作为短信的ID。 不要依靠短信内容和发件人作为短信的标识符。

因为getExtras()创build了一个intent extras的副本。

你必须这样做

 getIntent().removeExtra("smsChallenge"); 

文档: http : //developer.android.com/reference/android/content/Intent.html#removeExtra(java.lang.String)

“意图始终是开展这项活动的原始意图,只不过是一成不变的。” 黛安娜哈克博恩

要解决该问题,请首先确保将清单中的活动launchMode声明为singleTop。

然后从下面的讲话中 ,尝试使用onSaveInstanceState来logging你已经“消除”了一些额外的事实。 然后在onCreate中,检查它的“Bundle savedInstanceState”参数。 如果它不为null,那么它就是你之前在onSaveInstanceState中返回的Bundle。 从这个Bundle中,你可以决定忽略这些额外的事情。

编辑 :在你的情况下,使用共享偏好将允许你坚持状态,即使活动被破坏。

 public YourActivity extends Activity { private boolean extrasClearedOut; private SharedPreferences mPrefs; private static String EXTRA_CLEAR_OUT = "extras_cleared_out"; public void onCreate(Bundle savedInstanceState) { mPrefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); extrasClearedOut = mPrefs.getBoolean(EXTRA_CLEAR_OUT, false); if (savedInstanceState != null && savedInstanceState.getBoolean(EXTRA_CLEAR_OUT, false)) { extrasClearedOut = true; } Intent intent = getIntent(); if (extrasClearedOut) { // ignore the extras in the intent. } else { // Read and use the extras in the intent. } } protected void onNewIntent (Intent intent) { super.onNewIntent(intent); setIntent(intent); if (extrasClearedOut) { // ignore the extras in the intent. } else { // Read and use the extras in the intent. } } public void someMethod(...) { extrasClearedOut = true; } protected void onSaveInstanceState (Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean(EXTRA_CLEAR_OUT, extrasClearedOut); } public void onDestroy() { final Editor edit = mPrefs.edit(); edit.putBoolean(EXTRA_CLEAR_OUT, extrasClearedOut); edit.commit(); } } 

这是您的问题的另一个工作解决scheme

我认为你需要明确地设置你想要的行为的活动的意图。 我不知道为什么getIntent()似乎是返回一个副本。

Activity.setIntent()的文档

改变getIntent()返回的意图。 这是指给定的意图; 它不会复制它。 通常与onNewIntent(Intent)结合使用。

http://developer.android.com/reference/android/app/Activity.html#setIntent(android.content.Intent

 private void removeExtraFromBundle(String key){ Bundle bundle = getArguments(); if(bundle != null){ String value = null; value = bundle.getString(key); if(value != null){ bundle.remove(key); } } } 

上面的代码将帮助您从捆绑对象中删除特定的密钥。

我的build议是添加第三个额外的意图与一些nonce ,例如只是一个随机的string:

 final Intent activityIntent = new Intent(context, MainActivity.class); activityIntent.putExtra("smsChallenge", smsText); activityIntent.putExtra("smsSenderNumber", senderMobilNumber); activityIntent.putExtra("nonce", UUID.randomUUID().toString); activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); activityIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); context.startActivity(activityIntent); 

然后检查在onCreate()之前是否有这个随机数:

 public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent = getIntent(); smsChallenge = intent.getStringExtra("smsChallenge", null); String nonce = intent.getStringExtra("nonce", null); if (nonce == null) { // should not happen, but do something sane here } SharedPreferences sp = PreferenceManager.getDefaultPreferences(this); if (nonce.equals(sp.getString("nonce", null)) { // app was restarted } else { // app was started from a shiny fresh intent sp.edit().putString("nonce", nonce).commit(); } } 

但是请记住,方向改变等也在调用onCreate() 。 但是,通过检查savedInstanceState是否为null ,您可以很容易地savedInstanceState它。

去除额外的东西不是解决这个问题的正确方法。 由于用于启动所述活动的上下文,正在发生此问题。 改变这一点

 final Intent activityIntent = new Intent(context, MainActivity.class); 

对此

 final Intent activityIntent = new Intent(context.getApplicationContext(), MainActivity.class); 

当你按下后退button(假设你没有重载函数并改变它的行为),活动现在就完成了。 如果您将从应用程序列表中select应用程序,则不会包含任何附加内容。

编辑:

避免从接收器启动活动。 考虑一下:你在MainActivity上。 你收到短信。 现在,而不是更新ui反映新消息,你会看到一个新的活动正在推出,这将不是一个好的用户界面devise。

替代方法:更新您的数据库或做任何相关的行动需要完成。 然后在本地播放信息。 在你的活动注册这个广播接收器和刷新UI或做任何需要的。 如果您想通知用户而不是启动活动,请创build通知。