清算意图

我的Android应用程序正在通过传递信息的意图(pendingintent在状态栏)调用。

当我点击主页button,并通过按住home键重新打开我的应用程序,它再次调用意图和相同的演员仍然在那里。

@Override public void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); } @Override public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); } 

这是没有运行的代码

  String imgUrl; Bundle extras = this.getIntent().getExtras(); if(extras != null){ imgUrl = extras.getString("imgUrl"); if( !imgUrl.equals(textView01.getText().toString()) ){ imageView.setImageDrawable( getImageFromUrl( imgUrl ) ); layout1.setVisibility(0); textView01.setText(imgUrl);//textview to hold the url } } 

而我的意图是:

 public void showNotification(String ticker, String title, String message, String imgUrl){ String ns = Context.NOTIFICATION_SERVICE; NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns); int icon = R.drawable.icon; // icon from resources long when = System.currentTimeMillis(); // notification time CharSequence tickerText = ticker; // ticker-text //make intent Intent notificationIntent = new Intent(this, activity.class); notificationIntent.putExtra("imgUrl", imgUrl); notificationIntent.setFlags( PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT); //make notification Notification notification = new Notification(icon, tickerText, when); notification.setLatestEventInfo(this, title, message, contentIntent); //flags notification.flags = Notification.FLAG_SHOW_LIGHTS | Notification.FLAG_ONGOING_EVENT | Notification.FLAG_ONLY_ALERT_ONCE | Notification.FLAG_AUTO_CANCEL; //sounds notification.defaults |= Notification.DEFAULT_SOUND; //notify mNotificationManager.notify(1, notification); } 

有什么方法可以清除意图,或者检查之前是否使用过?

更新:

我没有意识到这个答案在5年前我第一次写的时候会被提及。

我会澄清指出,根据@ tato-rodrigo的回答,这不会帮助你在某些情况下检测已经处理的意图。

另外我应该指出,我把“清楚”放在引号中是有原因的 – 你并没有真正清除这个意图,你只是把这个额外的东西作为一个标志去除,这个标志已经被这个活动看到了。


我有完全相同的问题。

上面的答案让我走上正轨,我发现更简单的解决scheme,使用:

 getIntent().removeExtra("key"); 

方法调用“清除”意图。

自从一年前提出这个问题以后,这个问题有点晚了,但是希望这能够在未来帮助别人。

编辑:我正在编辑发布我正在使用的完整解决scheme。

如果问题是“活动从历史logging(最近的应用程序)启动时不执行一些代码”,此解决scheme将工作。

首先,在你的Activity声明一个boolean来表明Intent是否已经被使用:

  private boolean consumedIntent; 

然后,使用onSaveInstanceStateonCreate方法安全地存储和恢复此值,以处理configuration更改以及系统在进入后台时可能会终止您的Activity情况。

  private final String SAVED_INSTANCE_STATE_CONSUMED_INTENT = "SAVED_INSTANCE_STATE_CONSUMED_INTENT"; @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean(SAVED_INSTANCE_STATE_CONSUMED_INTENT, consumedIntent); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //set content view ... if( savedInstanceState != null ) { consumedIntent = savedInstanceState.getBoolean(SAVED_INSTANCE_STATE_CONSUMED_INTENT); } //other initializations } 

现在,检查你是否可以在onResume方法下运行你的代码。

  @Override protected void onResume() { super.onResume(); //check if this intent should run your code //for example, check the Intent action boolean shouldThisIntentTriggerMyCode = [...]; Intent intent = getIntent(); boolean launchedFromHistory = intent != null ? (intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0 : false; if( !launchedFromHistory && shouldThisIntentTriggerMyCode && !consumedIntent ) { consumedIntent = true; //execute the code that should be executed if the activity was not launched from history } } 

另外,如果您的Activity被configuration为singleTop ,那么当您传递一个新的Intent时,您应该重置您的标志。

  @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); consumedIntent = false; } 

麦克斯回答清除额外的作品:

  getIntent().removeExtra("key"); 

另一个有用的命令是:

  getIntent().setAction(""); 

您也可以通过调用以下标签来标记意图:

  getIntent().putExtra("used", true); 

然后只是检查价值。

 intent.replaceExtras(new Bundle()); intent.setAction(""); intent.setData(null); intent.setFlags(0); 

简单的答案是没有办法

长答案。 没有“一举一动”的意图。 从实验中可以看出,现代Android的最近活动历史不过是“意向历史”。 传递给活动的最新意图只是login到系统,这就是交易。 上面的人build议使用

 setAction("") 

但是它不起作用,因为意图已经logging,直到你在onNewIntent()或onStart()方法中得到它。

我通过避免意图来解决问题。 我的问题与作者发布的相似。 我试图通过通知区域的控制来实现全局退出。 它应该停止底层服务并closures应用程序的所有活动。 你可以在Waze应用程序中find相同的行为。

algorithm:

  1. 为通过“退出”操作传递给活动的通知控件创buildPendingIntent。 但对于一个简单的代理的特殊活动。
  2. 代理活动onStart()代码parsing意图,检查操作并将某个模型的状态设置为“Exited”。
  3. 代理活动onStart()代码使用setIntent(“”)清除原始意图,然后通过调用startActivity(intent)将其转发到目标“根”活动。
  4. 代理活动onStart()代码调用finish()。
  5. 在目标活动内部的onStart()和onNewIntent()检查模型状态,如果是“退出”(也在我的情况下调用stopService()),则调用finish()。

我希望这会有助于某人,因为我没有在互联网上find答案。

当我们从历史(最近的应用程序)启动Android应用程序,应用程序可以启动主要三个不同的意图标志。

  1. FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
    这是从最小化的应用程序的历史logging中启动的活动(长按Home键)。
    常量值: 1048576 (0x00100000)
  2. FLAG_ACTIVITY_NEW_TASK
    这是通过“点击应用程序图标”或“ 意图filter ”启动活动的时间。 这里的活动将成为这个历史堆栈的新任务的开始。
    常量值: 268435456 (0x10000000)
  3. FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY | FLAG_ACTIVITY_NEW_TASK
    这是当应用程序退出button,然后从历史(最近的应用程序)恢复。
    常数值: 269484032 (0x10100000)

常数值可以通过getIntent().getFlags()

在第三种情况下,Android从内存中重新加载最后一个Intent值。 所以你的应用程序的意图( getIntent )将有最后一个启动应用程序的意图的值。

实际上,应用程序应该performance得像是一次全新的发布,其意图是重新启动,而不是上次启动的意图值。 如果您通过单击应用程序图标来启动应用程序,则可以看到这种行为,它永远不会有旧的意图值。 这是因为Android在这种情况下使用了以下意图filter

  <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> 

但在第三种情况下(退出的应用程序是从最近应用程序的历史logging启动的),Android操作系统使用最后一个在退出之前启动应用程序的意图(通过按回退button)。 所以你最终有旧的意图价值和应用程序stream是不正确的。

去除意图是解决这个问题的一种方法,但是它不能完全解决问题! 随着Android操作系统从上次发布的应用程序重新加载意图,而不是最后一次启动意图的实例。

为了避免这种情况发生,干净的方法是通过获取Intenttypes来确定启动types。

因此,在您的LaunchActivity(在清单中定义了意图filter的那个)中,您可以在onCreate()onStart()onResume()方法中使用以下代码。

 if(getIntent().getFlags() == (Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY)) { //app is launched from recent apps after it was closed normalLaunch(); } else { String intentAction = getIntent().getAction(); String scheme = getIntent().getScheme(); //app is launched via other means // URL intent scheme, Intent action etc if("https".equalsIgnoreCase(scheme)) { // URL intent for browser } else if("com.example.bb".equalsIgnoreCase(intentAction)) { // App launched via package name } else { // App was launched via Click on App Icon, or other means normalLaunch(); } } 

我认为normalLaunch() ,不应该使用Intent的参数; 否则你将需要隔离和优化你的默认启动方法不使用意图参数。

确保您正在使用PendingIntent的PendingIntent.FLAG_UPDATE_CURRENT标志。

 PendingIntent pendingIntent = PendingIntent.getActivity(this, 100, mPutIntent, PendingIntent.FLAG_UPDATE_CURRENT); 

mPutIntent是你的Intent

希望这会帮助你。

当您完成处理意向时,请执行以下操作:

 setIntent(null); 

您将不会再看到已处理的Intent,并且您将不会通过编辑已处理的Intent的内容来掩盖问题。

我有完全相同的问题。 我的解决scheme是添加booleanvariables当Intent被“使用”, if基于这个boolean来检查是否应该使用Intent或不。

我最近有这个问题,我通过添加一个时间戳作为额外的参数来解决它的意图:

 private void launchActivity(Context context) { Intent intent = new Intent(context, MainActivity.class); intent.putExtra("KEY_EXTRA_TIMESTAMP", System.currentTimeMillis()); context.startActivity(intent); } 

之后,将时间戳保存到共享首选项:

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); long time = getIntent().getLongExtra("KEY_EXTRA_TIMESTAMP", -1); long previousTime = getPreferences(MODE_PRIVATE).getLong("timestamp", -1); //ignore if the timestamp is the same as the previous one if (time != previousTime) { handleIntent(getIntent()); if (time != -1) { //save the timestamp getPreferences(MODE_PRIVATE).edit().putLong("timestamp", time).apply(); } } } 

这样对我有用:

  Intent intent = getIntent(); intent.replaceExtras(new Bundle()); intent.setAction(""); intent.setData(null); intent.setFlags(0); 

即使在parsing后手动清除了Intent和Intent附加项之后,似乎Activity.getIntent()将始终返回启动Activity的原始Intent。

为了解决这个问题,我推荐这样的:

 public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // The Intent provided by getIntent() (and its extras) will persist through a restore // via savedInstance. Because of this, restoring this activity from a // an instance that was originally started with extras (deep-link or // pre-defined destination) may cause un-desired behavior // (ie...infinite loop of sending the user directly to somewhere else because of a // pre-defined alternate destination in the Intent's extras). // // To get around this, if restoring from savedInstanceState, we explicitly // set a new Intent *** to override the original Intent that started the activity.*** // Note...it is still possible to re-use the original Intent values...simply // set them in the savedInstanceState Bundle in onSavedInstanceState. if (savedInstanceState != null) { // Place savedInstanceState Bundle as the Intent "extras" setIntent(new Intent().putExtras(savedInstanceState)); } processIntent(getIntent()) } private void processIntent(Intent intent) { if (getIntent().getExtras() == null) { // Protection condition return; } doSomething(intent.getExtras.getString("SOMETHING_I_REALLY_NEED_TO_PERSIST")); final String somethingIDontWantToPersist = intent.getExtras.getString("SOMETHING_I_DONT_WANT_TO_PERSIST"); if(somethingIDontWantToPersist != null) { doSomething(somethingIDontWantToPersist); } } @Override public void onSaveInstanceState(Bundle savedInstanceState) { // Save selective extras from original Intent... savedInstanceState.putString("SOMETHING_I_REALLY_NEED_TO_PERSIST", "persistedValued"); super.onSaveInstanceState(savedInstanceState); } 

这样,有一种机制可以转储原始的Intent,同时仍然保留显式保留原始Intent / Intent附加组件某些部分的能力。

请注意,我没有testing过所有的Activity启动模式。

这将有希望帮助每个人。 所以首先我们得到意图

 //globally Intent myIntent; 

放在这个地方创build

 myIntent = getIntent(); String data = myIntent.getStringExtra("yourdata"); //Your process here 

现在让我们设置这个,每当我们的应用程序被破坏或退出,我们将删除数据

 @Override protected void onDestroy() { //TODO: Clear intents super.onDestroy(); myIntent.removeExtra("data"); } @Override protected void onBackPressed() { //TODO: Clear intents super.onBackPressed(); myIntent.removeExtra("data"); } 

你明白了,如果这还不够,只要find更多的“callback”callback

我无法find一种方法来删除意图额外 。 如果您从开发人员选项中启用“不要保留活动 ”(这样您可以销毁活动并返回来testingExtras是否存在),那么没有任何关于从意图中删除多余的答案。

作为解决这个问题的方法,我在处理了Intent Extras之后,在SharedPreferences中存储了布尔值。 当同样的Intent被重新传递给Activity时,我检查SharedPreference值并决定处理Intent Extra。 如果您将另一个新的Intent Extra发送到同一活动,则将SharedPreference值设置为false,并由Activity进行处理。 例如

 // Start Activity with Intent Extras Intent intent = new Intent(context, MyActivity.class); intent.putExtra("someData", "my Data"); // Set data as not processed context.getSharedPreferences(BuildConfig.APPLICATION_ID, Context.MODE_PRIVATE).edit().putBoolean("myActivityExtraProccessed", false).commit(); context.startActivity(intent); ... public class MyActivity{ ... public void someMethod(){ boolean isExtrasProcessed = context.getSharedPreferences(BuildConfig.APPLICATION_ID, Context.MODE_PRIVATE).getBoolean("myActivityExtraProccessed", false); if (!isExtrasProcessed) { // Use Extras //Set data as processed context.getSharedPreferences(BuildConfig.APPLICATION_ID, Context.MODE_PRIVATE).edit().putBoolean("myActivityExtraProccessed", true).commit(); } } } 

直接的方法是避免从onCreate()以外的方法调用getIntent()。 但是,如果用户通过点击主页button离开我们的活动,这会在下次启动时造成问题。 我认为这个问题没有一个完整的function解决scheme。

这个怎么样? 将newIntent设置为意图。

 @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); } 

如果你想清除意图,用空的replace它呢?

例如。

 @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); } @Override public void onResume() { super.onResume(); Intent theIntent = getIntent(); if ("myaction".equals(theIntent.getAction()) { handleIntent(); onNewIntent(new Intent()); // <--- "clear" the intent by setting empty one } } 
 Intent intent = new Intent(Intent.ACTION_MAIN); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addCategory(Intent.CATEGORY_HOME); startActivity(intent); 

虽然Intent.removeExtra("key")会从extras中移除一个特定的键,但是Intent.replaceExtras(Bundle)方法也可以用来从Intent中删除整个的extras,如果null作为参数。

从文档:

用给定的附加组件完全replace意图中的附加组件。

参数
extras (额外)Intent中的新组件,或者null来清除所有额外组件。

因为putXXX()方法初始化一个新的Bundle,如果它是空的,这是没有问题的。