Intent with old extra in onCreate() for singleTask

2019-02-22 06:11发布

问题:

For example I created project with 2 activities: FirstActivity with android:launchMode="singleTask" flag and SecondActivity.

At first user starts FirstActivity and after this SecondActivity will start on button click. From SecondActivity we create status bar notification.

Intent intent = new Intent(SecondActivity.this, FirstActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(FirstActivity.ARG, true);

NotificationCompat.Builder builder = new      NotificationCompat.Builder(SecondActivity.this);
builder.setSmallIcon(R.drawable.ic_launcher)
   .setAutoCancel(true)
   .setContentTitle("title")
   .setContentText("message");

PendingIntent notifyIntent = PendingIntent.getActivity(SecondActivity.this, 0,     intent,PendingIntent.FLAG_CANCEL_CURRENT);
builder.setContentIntent(notifyIntent);

NotificationManager notificationManager = (NotificationManager)   getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(1000, builder.build());

When I clicked on this notification and my application is running now, FirstActivity#onNewIntent method will be executed and intent contains ARG extra = true. It's Ok situation.

When I clicked on this notification and my application is NOT running now, FirstActivity#onNewIntent method will NOT be executed, but instead of this FirstActivity#onCreate() will be executed and I can get my ARG flag like getIntent().getBooleanExtra(ARG, false) This intent contains ARG extra = true. It's correct situation too.

But when I try exit from my app after Situation 2 pressing back button and run app again, I received in FirstActivity#onCreate() intent with ARG = true (old extra value which I handled). Why my flag is "true" after re-open app?

回答1:

I came across this question while looking for a solution to a similar problem. Even though this question is from an year ago, I’ll write down how I solved it in case it can help somebody else because it took me many many hours to solve my problem. I also have the activity declared with the android:launchMode as “singleTask”. A notification is sent from a service and this notification has a PendingIntent with an Intent to open MyActivity.

My solution is to set the flag FLAG_ACTIVITY_NEW_TASK (http://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_NEW_TASK) in the intent. Then create the Pending intent with id 0 and PendingIntent.FLAG_CANCEL_CURRENT.

Intent _intent = new Intent(context, MyActivity.class);
_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
_intent.putExtra("DATA", myData);

PendingIntent _pIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);

Whenever the notification is clicked an instance of MyActivity is created in a new task and onCreate is called. The Intent contains the correct extra data. When I press the back button and there is a new notification, the intent always brings the newest extra data. If an instance of the activity already exists (for example when I press the Home Screen button), onNewIntent method is called and the intent brings the correct new extra data.

This is clearly explained in http://developer.android.com/guide/topics/manifest/activity-element.html#lmode. I also tried using different request codes (arg 2) per notification in PendingIntent.getActivity and with PendingIntent.FLAG_UPDATE_CURRENT but I think the secret is in the definition of launchMode as singleTask and Intent.FLAG_ACTIVITY_NEW_TASK.

I also have another case in which the launchMode is "standard". Here the activity is also started by clicking a notification sent from a service. In order to have the started activity receive the correct extra data I set the flag FLAG_ACTIVITY_SINGLE_TOP.

_intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);

This flag makes the method onNewIntent to be called when an instance of the activity already exists (When I pressed Home Screen button for example). Again with the correct extra data. Otherwise onCreate is called also with the correct extra data (When I pressed the back button for example).

The Pending intent is created with a new request code every time but it should work also with the same request code. I think the secret is in the launchMode and the intent flag set.

PendingIntent pIntent = PendingIntent.getActivity(this, notificationRequestCode, _intent, PendingIntent.FLAG_CANCEL_CURRENT);