Clearing intent

2020-01-25 13:29发布

My Android app is getting called by an intent that is passing information (pendingintent in statusbar).

When I hit the home button and reopen my app by holding the home button it calls the intent again and the same extras are still there.

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

this is the code that doesn't run like its supposed to

    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

        }

    }

And my intent:

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

Is there any way to clear the intent or check whether it has been used before?

19条回答
小情绪 Triste *
2楼-- · 2020-01-25 14:01

When you are done processing the Intent, do this:

setIntent(null);

You won't see that processed Intent again, and you won't be masking the problem by editing the contents of the processed Intent.

查看更多
在下西门庆
3楼-- · 2020-01-25 14:02
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
intent.addCategory(Intent.CATEGORY_HOME);  
startActivity(intent);
查看更多
放我归山
4楼-- · 2020-01-25 14:06

I recently had this problem and I solved it by adding a timestamp as a extra parameter to the intent:

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

After that, save the timestamp to the shared preferences:

@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();
        }
    }
}
查看更多
冷血范
5楼-- · 2020-01-25 14:06

Even after manually clearing the Intent and Intent extras after they have been parsed, it seems as though Activity.getIntent() will always return the original Intent that started the Activity.

To get around this, I recommend something like this :

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

This way, there is a mechanism to dump the original Intent while still retaining the ability to explicitly retain certain parts of the original Intent / Intent extras.

Note that I haven't tested all Activity launch modes.

查看更多
该账号已被封号
6楼-- · 2020-01-25 14:07

Short answer is No way

Long answer. There is no such thing as "one-shot" intent. From experiment it is observed that recent activity history in modern Androids is nothing more than "Intent history". The latest intent passed to activity is simply logged into system and that's the deal. Folks above suggest to use

setAction("")

But it does not work because the intent is already logged till the moment you get it inside onNewIntent() or onStart() method.

I solved the problem by avoiding use of intents. My problem was simmiliar to the one posted by the author. I tried to implement Global Exit from application via control in notification area. It should stop the underlying service and close all activities of the app. You can find same behavior in Waze application.

The algorithm:

  1. Create PendingIntent for notification control which passes "Exit" action to activity. But to the special activity which is a simple proxy.
  2. Proxy activity onStart() code parses the intent, checks action and sets the state of some model to "Exited".
  3. Proxy activity onStart() code clears original intent using setIntent("") and then forwards it to destination "Root" activity by calling startActivity(intent).
  4. Proxy activity onStart() code invoke finish().
  5. Inside onStart() and onNewIntent() of destination activity check model state and call finish() if it is "Exited" (and also call stopService() in my case).

I hope this will help to someone because I did not find the answer in the internet.

查看更多
一夜七次
7楼-- · 2020-01-25 14:07

I've got exactly the same problem. My solution was to add boolean variable that was set when Intent was 'used' and if statement based on this boolean to check if you should use Intent or not.

查看更多
登录 后发表回答