Android - 清除任务标志不适用于 PendingIntent

Posted

技术标签:

【中文标题】Android - 清除任务标志不适用于 PendingIntent【英文标题】:Android - Clear task flag not working for PendingIntent 【发布时间】:2014-09-12 10:22:56 【问题描述】:

我有一个 A > B > C 的任务堆栈。我目前在 C 上,然后我按下主页按钮。我收到一条通知,打算将我带到活动 A。我按下通知,我在 A,但如果我按回去,我转到 C,然后是 B,然后是 A。

我正在像这样设置我的 PendingIntent。有什么明显的问题吗?

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

编辑 1:

我在这里尝试了这个建议: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);

但我仍然得到相同的结果。我的活动 A 在我的应用程序任务堆栈中开始,我按下返回并转到 C,然后是 B,然后是 A。

我开始认为这在 android 中是不可能的,或者在使用挂起的 Intent 时是不可能的。

编辑 2: 这不是需要什么标志的问题。更多的问题是标志似乎没有效果。

【问题讨论】:

明确地说,您想返回 A 并从堆栈中删除 B 和 C? 我想返回 A 并删除 B 和 C,但我不确定我是否只是希望 A 恢复或 A 也被删除,并启动 A 的新实例。 @DanS 无论哪种方式。我需要清除 B 和 C。当我可以进行清算时,我会检查 A 的行为。 ActivityA 中你有onNewIntent() 实现了吗? @DanS 不。我还没有听说过这种方法,但我想专注于从堆栈中正确清除 B 和 C。 【参考方案1】:

如果您使用解决方案 1,那么只需从清单中删除 launchMode="singleTask"

1)

 final Intent notificationIntent = new Intent(mContext, ActivityA.class);

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

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

2)

       <activity 
       android:name=".ActivityA" 
       android:theme="@style/theme_noActionBar" 
       android:noHistory="true">

3)

<activity android:name=".ActivityA" android:launchMode="singleTop">

【讨论】:

选项 2 对我有用,选项 1 在我的情况下根本没有帮助 选项 2 为我唤醒了 仅当 Intent 具有非空操作时,选项 1 才适用于我。为什么?! ...或者当PendingIntent 具有非零requestCode 卸载并重新安装该应用程序使 OP 的原始代码对我有用,正如以下晦涩的答案之一所建议的那样 (CLEAR_TOP | NEW_TASK)【参考方案2】:

我在这方面遇到了很多问题,并认为我要疯了,直到我卸载/重新安装了我的应用程序,嘿,很快,代码按照 Stack Overflow 上的许多帖子工作。我正在执行以下操作:

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

并且不断获得该应用程序的两个版本。在一台设备上卸载并重新启动另一台设备后,现在所有的行为都与单个实例的预期一样。希望对您有所帮助。

【讨论】:

我的也需要重启才能使新的 Intent.FLAG_ACTIVITY_CLEAR_TOP 工作! 遗留答案永远不会过时! :D 它也让我发疯,重新启动应用程序是它工作的原因。非常感谢分享这个。 是的 卸载并重新安装解决了我的问题。【参考方案3】:

您遇到的问题与 Android 使用您的 PendingIntent 和所需的 Intent.FLAG_ACTIVITY_NEW_TASK 创建新任务有关。换句话说,您要使用的标志与在给定任务堆栈的上下文中启动活动有关。 PendingIntent 通常没有上下文,因此您看到的是正在为您的 Activity A 未决意图创建的任务。

这是对文档的参考:

Android PendingIntent

要求PendingIntents 系列中的第一个具有Intent.FLAG_ACTIVITY_NEW_TASK 是问题所在。请注意,一系列待处理的意图可以与使用“getActivities”方法的初始待处理意图具有相同的上下文。

你说得对,只使用标志是不可能做你想做的事的。您的代码是正确的,要获得您想要的行为,您还需要超越意图标志。

还有很多其他方式,比如使用清单、运行服务、使用静态字段等来尝试管理您感兴趣的事情。除此之外,如果您决定走使用 Manifest 的路线,您可以使用TaskStackBuilder 来解决您的问题。还有很多其他不涉及标志的解决方案,但是您专门询问了使用标志的问题。

【讨论】:

【参考方案4】:

您可以在Manifest文件中将ActivityA的launchMode设置为singleTask。因为ActivityA 是你的应用程序的根,所以它可以工作。

来自documentation:

系统在新任务和路由的根目录创建活动 它的意图。但是,如果活动的一个实例已经 存在,系统通过 调用它的 onNewIntent() 方法,而不是创建一个新方法。

        <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>

编辑 1:

由于您不想修改 Manifest 文件,我能看到的唯一选项是使用 Intent.makeRestartActivityTask 方法生成 Intent。但是,这将重新启动 ActivityA 而不是恢复现有实例。

Intent intent = Intent.makeRestartActivityTask(new ComponentName(this, ActivityA.class));
PendingIntent rIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, 0);

【讨论】:

这可以工作,但如果我想将我的待定意图更改为活动 B,那么设置单个任务会给我带来问题。我应该能够在不修改清单的情况下设置一个 Intent.FLAG 来执行此操作。 makeRestartActivityTask 就像一个魅力!谢谢 我不知道为什么,但这是唯一适合我的选择。我有一个期望结果的外部应用程序启动的活动,并在我自己的应用程序中使用 NFC + 挂起意图,这完全破坏了我的应用程序在我只使用 NEW_TASK 时所做的结果设置。【参考方案5】:

意图标志的解决方案如下:

    在 Manifest 中,为活动 A 添加 launchMode:singleTask

    使用以下代码块:

    final Intent notificationIntent = new Intent(mContext, ActivityA.class);
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    PendingIntent contentIntent = PendingIntent.getActivity(myContext, 0, notificationIntent, 0);
    

这里发生的情况是,当使用通知启动 Activity A 时,根据Intent.FLAG_ACTIVITY_NEW_TASK 的定义,由于存在一个包含 A 的任务 A>B>C,因此该任务被提出,同时破坏了活动 B 和 C 并且A以onNewIntent --&gt; onRestart --&gt; onStart --&gt; onResume开头

如果您现在正在启动的 Activity 的任务已在运行,则该任务将被带到前台并恢复其最后状态,并且该 Activity 在 onNewIntent() 中接收新意图

现在的原因是,仅使用 Intent 标志时它表现不佳的原因是,Activity A 不是以 singleTask 模式启动的,并且 Android 不知何故无法保持它的状态。

【讨论】:

【参考方案6】:

尝试使用 Intent 标志 FLAG_ACTIVITY_CLEAR_TOP 而不是清除任务。来自Intent documentation:

如果设置,并且正在启动的活动已经在 当前任务,而不是启动该任务的新实例 活动,其之上的所有其他活动都将关闭,并且 此 Intent 将作为 新意图。

例如,考虑由以下活动组成的任务:A、B、C、D。 如果 D 调用 startActivity() 的 Intent 解析为 活动B的组成部分,然后C和D将完成,B收到 给定的 Intent,导致堆栈现在是:A,B。

【讨论】:

刚试过。与我的问题中提到的行为相同。【参考方案7】:

我的解决方案代码:

    public class MyApplication extends Application
    private static int activityCounter;
    public Activity A,B,C;
    public void incrementActivityCounter()
    
        activityCounter++;
    
    public void decrementActivityCounter()
    
        activityCounter--;
        if (activityCounter == 0)
        
            A.finish();
            B.finish();
            C.finish();
        
    



public class A extends Activity
   @Override
    protected void onStart()
    
        super.onStart();
        application.incrementActivityCounter();
    

    @Override
    protected void onStop()
    
        application.decrementActivityCounter();
        super.onStop();
    

【讨论】:

【参考方案8】:

我创建了一个演示项目作为您的描述,它可以按照您的要求工作。

我不知道你是怎么得到通知的,所以在我的项目中我使用了一个BroadcastReceiver来获取一个Broadcast,然后在Receiver的onReceive()方法中显示这个Notification。我认为您可以将我的演示与您的项目进行比较以找出问题所在。顺便说一句,我的测试是在 API 16 下进行的。

这是我的演示: https://github.com/leoguo123/AndroidDemo

在存储库中:

测试项目包含 3 个 Activity(A > B > C),它可以在收到正确的广播时显示通知。 SendBroadcast 项目负责发送广播。

生成通知的代码:

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

【讨论】:

【参考方案9】:

尝试了上面的所有建议但都失败了,并从https://***.com/a/24999724/4271334 和https://***.com/a/26592562/4271334 的指南中找到了解决方案。 在清单中添加以下 2 行

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

并使用

在 NotificationCompat.Builder 设置 PendingIntent
mBuilder.setContentIntent(addBackStack(mContext,intent));

在哪里

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

希望有人能得到帮助。

【讨论】:

以上是关于Android - 清除任务标志不适用于 PendingIntent的主要内容,如果未能解决你的问题,请参考以下文章

Gradle Maven 插件“安装”任务不适用于 Android 库项目

Ccache 不适用于 gcc -M 标志?

瑞典语标志不适用于 SQL 查询

清除 android 活动堆栈开始一个新活动

带有标志 --legacy-watch 的 Nodemon 不适用于 docker Ubuntu/Linux

Bash grep 不适用于撇号