Android - Clear task flag not working for PendingI

2019-01-26 05:27发布

I have a task stack of A > B > C. I am currently on C, and then I press the home button. I get a notification with the intent to take me to Activity A. I press the notification, and I'm at A but if I press back, I go to C, then B, then A.

I am setting up my PendingIntent like so. Anything clearly wrong with it?

final Intent notificationIntent = new Intent(mContext, ActivityA.class);
        notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);


        PendingIntent contentIntent = PendingIntent.getActivity(myContext, 0, notificationIntent, 0);

EDIT 1:

I tried the suggestion here: Clear all activities in a task?

notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);

but I still get the same result. My activity A starts in my application task stack, I press back and go to C, then B, then A again.

I am starting to think that this is either not possible in Android or it's not possible when using a pending intent.

EDIT 2: This is not a matter of what flags are needed. More of an issue of what could be going wrong that the flags seem to have no effect.

9条回答
萌系小妹纸
2楼-- · 2019-01-26 05:57

You can set the launchMode of ActivityA to singleTask in Manifest file. Since ActivityA is the root of your application it works.

From documentation:

The system creates the activity at the root of a new task and routes the intent to it. However, if an instance of the activity already exists, the system routes the intent to existing instance through a call to its onNewIntent() method, rather than creating a new one.

        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:launchMode="singleTask" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

EDIT 1:

Since you don't want to modify Manifest file, only option I can see is using Intent.makeRestartActivityTask method to generate the Intent. However this will relaunch the ActivityA rather than resuming existing instance.

Intent intent = Intent.makeRestartActivityTask(new ComponentName(this, ActivityA.class));
PendingIntent rIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, 0);
查看更多
Juvenile、少年°
3楼-- · 2019-01-26 05:59

Tried all suggestions from above and failed and the came up with a solution from the guideline from https://stackoverflow.com/a/24999724/4271334 and https://stackoverflow.com/a/26592562/4271334. Added following 2 lines in the manifest

android:launchMode="singleTask"
android:clearTaskOnLaunch="true"

and set the PendingIntent at NotificationCompat.Builder using

mBuilder.setContentIntent(addBackStack(mContext,intent));

where

public static PendingIntent addBackStack(final Context context, final Intent intent) {
    TaskStackBuilder stackBuilder = TaskStackBuilder.create (context.getApplicationContext ());
    stackBuilder.addNextIntentWithParentStack (intent);
    intent.addFlags (Intent.FLAG_ACTIVITY_NEW_TASK);
    return stackBuilder.getPendingIntent (0,PendingIntent.FLAG_UPDATE_CURRENT);
}

Hope someone will be helped.

查看更多
乱世女痞
4楼-- · 2019-01-26 06:02

Try using the Intent flag FLAG_ACTIVITY_CLEAR_TOP instead of clearing the task. From the Intent documentation:

If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.

For example, consider a task consisting of the activities: A, B, C, D. If D calls startActivity() with an Intent that resolves to the component of activity B, then C and D will be finished and B receive the given Intent, resulting in the stack now being: A, B.

查看更多
甜甜的少女心
5楼-- · 2019-01-26 06:06

I created a demo project as your description and it works just as what you want.

I don't know how do you get the notification, so in my project I use a BroadcastReceiver to get a Broadcast and then show the Notification in the onReceive() method of the Receiver. I think you can compare my demo with your project to find the problem. BTW, my test is performed under API 16.

Here is my demo: https://github.com/leoguo123/AndroidDemo

In the repository:

Test project contains 3 Activity(A > B > C) and it can show the Notification when receive a proper broadcast. SendBroadcast project is responsible for sending the broadcast.

The code for generating the notification:

    public class MyBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        showNotification(context);
    }

    private void showNotification(Context context) {
        Intent intent = new Intent(context, ActivityA.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
                | Intent.FLAG_ACTIVITY_SINGLE_TOP
                | Intent.FLAG_ACTIVITY_NEW_TASK);
        NotificationManager nmr = (NotificationManager) context
                .getSystemService(Context.NOTIFICATION_SERVICE);
        PendingIntent pi = PendingIntent.getActivity(context, 0, intent, 0);
        Notification.Builder builder = new Notification.Builder(context);
        builder.setContentTitle("Open A with B and C being closed");
        builder.setContentText("Open A with B and C being closed");
        builder.setSmallIcon(R.drawable.ic_launcher);
        builder.setContentIntent(pi);
        builder.setAutoCancel(true);
        Notification nt = builder.build();
        nmr.notify(0, nt);
    }
}
查看更多
趁早两清
6楼-- · 2019-01-26 06:12

I had loads of problems with this, and thought I was going crazy until I uninstalled/reinstalled my App and hey presto, the code works as per many posts on Stack Overflow. I was doing the following:

Intent i = new Intent(getApplicationContext(), MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);

PendingIntent pi = PendingIntent.getActivity(this, 0, i, 0);

and was continually getting two versions of the App. After an uninstall on one device, and re-starting the other device everything now behaves as expected with a single instance. Hope this helps you.

查看更多
仙女界的扛把子
7楼-- · 2019-01-26 06:15

The problem you are encountering has to do with Android creating a new task using your PendingIntent and the required Intent.FLAG_ACTIVITY_NEW_TASK. In other words, the flags you are wanting to use have to do with starting activities within the context of a given task stack. A PendingIntent usually does not have a context, and therefore what you are seeing is a task being created for your Activity A pending intent.

Here's the reference to the docs:

Android PendingIntent

The requirement for the first in a series of PendingIntents to have Intent.FLAG_ACTIVITY_NEW_TASK is the issue. Note that a series of pending intents can have the same context as the initial pending intent using the "getActivities" method.

You are correct that it is not possible to do what you want only using flags. Your code is correct, and to get the behavior that you want you will need too look beyond intent flags.

There are many other ways, such as using the manifest, running a service, using static fields, etc. to try to manage what you are interested in doing. Besides that, you could possibly use TaskStackBuilder to solve your problem if you decide to go the route of using the Manifest. There are also many other solutions not involving flags, but you specifically asked about using flags.

查看更多
登录 后发表回答