目的明确

我的 Android 应用程序正在被一个传递信息的意图调用(状态栏中的 Pending)。

当我点击 home 按钮,按住 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);
}

是否有任何方法可以澄清其意图或检查其是否以前使用过?

90057 次浏览

我也有同样的问题。我的解决方案是添加 boolean变量,这是在 Intent被“使用”时设置的,并根据这个 boolean添加 if语句,以检查是否应该使用 Intent

更新:

当我5年多前第一次写这个问题的时候,我没有意识到这个答案会被提到这么多!

我将澄清指出,作为每@tato-Rodrigo 的回答,在某些情况下,这不会帮助您检测已经处理好的意图。

我还要指出的是,我在引号中加上“ clear”是有原因的——通过这样做,你真的是在清除 没有的意图,你只是在使用移除额外的意图作为一个标志,这个意图已经被活动看到了。


我也有同样的问题。

上面的答案让我找到了正确的方向,我发现了更简单的解决方案,使用:

getIntent().removeExtra("key");

方法调用来“清除”意图。

这是一个有点晚的回答,因为这是一年前的问题,但希望这有助于其他人在未来。

Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addCategory(Intent.CATEGORY_HOME);
startActivity(intent);

马克斯的回答对于清除额外的工作:

    getIntent().removeExtra("key");

另一个有用的命令是:

    getIntent().setAction("");

你也可以通过调用:

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

然后检查价值。

这个怎么样? 设置 newIntry 作为意图。

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

简单来说就是 不可能

答案很长。没有所谓的“一击即中”的意图。从实验中可以看出,现代机器人的近代活动史不过是“意图史”。传递给活动的最新意图只是简单地登录到系统中,这就是交易。上面的人建议使用

setAction("")

但是它不工作,因为意图已经被记录,直到您将其放入 onNewInent ()或 onStart ()方法中。

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

算法:

  1. 为通知控件创建 PendingInent,该控件将“ Exit”操作传递给活动。但是对于特殊活动来说,这只是一个简单的代理。
  2. 代理活动 onStart ()代码解析意图,检查动作,并将某个模型的状态设置为“退出”。
  3. 代理活动 onStart ()代码使用 setInent (“”)清除原始意图,然后通过调用 startActivity (intent)将其转发到目标“ Root”活动。
  4. 代理活动 onStart ()代码调用 Finish ()。
  5. 在目标活动的 onStart ()和 onNewInent ()内部,检查模型状态,如果模型状态为“ Exted”,则调用 Finish ()(在我的例子中,还调用 stopService ())。

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

虽然 Intent.removeExtra("key")将从临时值中删除一个特定的键,但是还有一个方法 替换额外功能(捆绑),如果将 null作为参数传递,则可以使用它来删除意图中的所有临时值。

来自文件:

将意图中的额外内容完全替换为给定的 临时演员。

参数
意图中的一组新的附加值,或者用 null 擦除所有附加值。

因为 putXXX ()方法使用一个新的 Bundle 初始化额外的元素,如果它是 null 的话,这就没有问题了。

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

如果问题是 “当活动从历史记录(最近的应用程序)开始时不执行某些代码”,这个解决方案将会有效。

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

    private boolean consumedIntent;

然后,使用 onSaveInstanceStateonCreate方法安全地存储和恢复这个值,以处理配置更改和系统可能在 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配置为 singleTop,您应该在交付新的 Intent时重置您的标志。

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

当你希望清除意图时——用一个空的意图替换它怎么样?

例如。

@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.replaceExtras(new Bundle());
intent.setAction("");
intent.setData(null);
intent.setFlags(0);

确保对 未决意图使用 FLAG _ UPDATE _ CURRENT标志。

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

其中 mPutIntent是你的 Intent

希望这个能帮到你。

处理完意图后,执行以下操作:

setIntent(null);

您不会再次看到处理过的意图,也不会通过编辑处理过的意图的内容来掩盖问题。

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

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();
}
}
}

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

  1. FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
    这是当活动是从一个应用程序的历史被最小化(长按主键)启动。
    常数值: 1048576(0x00100000)
  2. FLAG_ACTIVITY_NEW_TASK
    这是当活动启动通过“点击应用程序图标”或通过“ 意图过滤器”。在这里,活动将成为这个历史堆栈上新任务的开始。
    常数值: 268435456(0x10000000)
  3. FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY | FLAG_ACTIVITY_NEW_TASK
    This is when app was quit by pressing back button and then resumed from History (recent apps).
    常数值: 269484032(0x10100000)

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

在第三种情况下,Android 从其内存中重新加载最后的意图值。因此,你的应用程序的意图(getIntent)将有值从上次启动应用程序的意图。

实际上,应用程序应该表现得就像是一个新的发布,带有一个新发布的意图值,而不是之前发布的意图值。如果你通过点击应用程序图标来启动应用程序,就可以看到这种行为,它永远不会有旧的意图值。这是因为 Android 在这个场景中使用了以下意图过滤器

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

但是在第三种情况下(退出的应用程序是从历史上最近的应用程序启动的) ,Android 操作系统使用了在退出之前启动应用程序的最后意图(通过按下后退按钮)。因此,你最终会有旧的意图值和应用程序流程是不合适的。

移除意图是解决问题的一种方法,但它不能完全解决问题!因为 Android 操作系统从上次启动的应用程序中重新加载了意图,而不是最后一次启动意图的实例。

避免这种情况发生的一个干净的方法是,通过获取 意图类型来确定启动类型来处理它。

因此,在 LaunchActivity (在清单中定义了意图过滤器的那个)中,可以在 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()不应该使用来自意图的参数; 否则您将需要隔离和优化默认启动方法,以避免使用意图参数。

即使在解析意图和意图附加部分之后手动清除它们之后,Activity.getInent ()似乎总是返回启动活动的原始意图。

为了解决这个问题,我建议这样做:

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);
}

通过这种方式,有一种机制可以转储原始意图,同时仍然保留显式保留原始意图/意图附加的某些部分的能力。

注意,我还没有测试所有的 Activity 启动模式。

希望这能帮到大家。 所以首先我们要知道他们的意图

//globally
Intent myIntent;

把这个放在 Create 的某个地方

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");
}

你得到的想法,如果这还不够,只是找到更多的’上’回调

我无法找到一种方法来删除意图额外 。如果你从开发者选项中启用了 ”不要保留活动,那么关于 从意图中去除额外的东西的所有答案都不起作用(这样你就可以破坏活动,然后回来测试是否还有额外的东西)。

作为问题的 解决方案,在处理完意图附加值后,我将布尔值存储在 共享偏好中。当相同的意图被重新提交到 Activity 时,我检查 SharedPreferences 值并决定处理意图附加值。如果您向同一个 Activity 发送另一个新的 IntentUltra,那么您将 SharedPreferences 值设置为 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 ()以外的方法调用 getInent ()。但是,如果用户通过点击 Home 按钮离开我们的 Activity,那么在下次启动时将会出现问题。我认为这个问题没有一个完整的功能性解决方案。

我遇到了同样的问题,并尝试使用上述方法,但它不工作。

我认为这可能是活动的启动模式的原因,我使用的是 singleTop 模式。

当我后台应用程序和使用 RamEater 模拟问题,意图总是有额外的,甚至我设置它为空或删除键。

通过在 Android 上使用首选项存储来检查已经通过的问题已经解决了。

仅仅为了知道是否已经使用了额外的内容而添加另一个额外的内容并不是一个好的做法,为什么不这样做呢?:

if (intent.hasExtra(EXTRA_NAME) && intent.getBooleanExtra(EXTRA_NAME, false)) {
// consume extra here after that set it to false
putExtra(EXTRA_NAME, false)
}

这招对我很管用。

private void getTheIntent() {
if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0
| (getIntent().getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {


Log.i(TAG, "getTheIntent: Not from History !!!!!!!!!!!!!!!!!!!!!");
// add your code .
}
else{
Log.i(TAG, "getTheIntent: Launched from History !!!!!!!!!!!!!!!!!!!!!");
//the activity is launched from history after being closed by back button or home button
// it will go here and the above code will not be repeated.
}


}